poliorcetics / cargo-intraconv Goto Github PK
View Code? Open in Web Editor NEWA simple helper to transform Markdown links to intra-doc links in Rust projects when appropriate.
License: MIT License
A simple helper to transform Markdown links to intra-doc links in Rust projects when appropriate.
License: MIT License
-//!
-#![doc(html_root_url = "https://docs.rs/tracing-appender/0.1.1")]
+
This link should not have been removed:
-//! [non_blocking]: mod@non_blocking
-//! [docs-url]: https://docs.rs/tracing-serde
+//! [docs-url]: tracing_serde
warning: unresolved link to `tracing_serde`
--> tracing-serde/src/lib.rs:9:17
|
9 | //! [docs-url]: tracing_serde
| ^^^^^^^^^^^^^ no item named `tracing_serde` in scope
Instead it should be [docs-url]: crate
.
-
is from yesterday's branch, +
is from today.
-/// [`SpanTrace`]: super::SpanTrace
+/// [`SpanTrace`]: ../struct.SpanTrace.html
-//! [`env_logger`]: env_logger/index.html
+//! [`env_logger`]: env_logger::
Currently, every time I run intraconv, it changes this link:
- /// [`downcast_ref`]: #method.downcast_ref
+ /// [`downcast_ref`]: Collect::downcast_ref()
That breaks because downcast_ref
is a function on dyn Collect
, not Collect
itself. There's no way for intra-conv to know this, so I don't think it can be fixed on that end, but it would be nice to say "I know this link will break, don't convert it" with a configuration file or something.
Similarly
//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
//! [span]: tracing::span
gets converted every time, which breaks because tracing
isn't in scope in tracing-attributes
(rust-lang/rust#74481).
$ cargo intraconv -i
...
$ git d -w tracing-subscriber/src/registry/sharded.rs
... entire file is deleted ...
+#[cfg(feature = "registry")]#[cfg_attr(docsrs, doc(cfg(feature = "registry")))]#[derive(Debug)]pub struct Data<'a> { /// Immutable reference to the pooled `DataInner` entry. inner: Ref<'a, DataInner>,}/// Stored data associated with a span.////// This type is pooled using `sharded_slab::Pool`; when a span is dropped, the/// `DataInner` entry at that span's slab index is cleared in place and reused/// by a future span. Thus, the `Default` and `sharded_slab::Clear`/// implementations for this type are load-bearing.#[derive(Debug)]struct DataInner { metadata: &'static Metadata<'static>, parent: Option<Id>, ref_count: AtomicUsize, // The span's `Extensions` typemap. Allocations for the `HashMap` backing // this are pooled and reused in place. pub(crate) extensions: RwLock<ExtensionsInner>,}// === impl Registry ===impl Default for Registry { fn default() -> Self { Self { spans: Pool::new(), current_spans: ThreadLocal::new(), } }}#[inline]fn idx_to_id(idx: usize) -> Id { Id::from_u64(idx as u64 + 1)}#[inline]fn id_to_idx(id: &Id) -> usize { id.into_u64() as usize - 1}/// A guard that tracks how many [`Registry`]-backed `Subscriber`s have/// processed an `on_close` event.////// This is needed to enable a [`Registry`]-backed Subscriber to access span/// data after the `Subscriber` has recieved the `on_close` callback.////// Once all `Subscriber`s have processed this event, the [`Registry`] knows/// that is able to safely remove the span tracked by `id`. `CloseGuard`/// accomplishes this through a two-step process:/// 1. Whenever a [`Registry`]-backed `Subscriber::on_close` method is/// called, `Registry::start_close` is closed./// `Registry::start_close` increments a thread-local `CLOSE_COUNT`/// by 1 and returns a `CloseGuard`./// 2. The `CloseGuard` is dropped at the end of `Subscriber::on_close`. On/// drop, `CloseGuard` checks thread-local `CLOSE_COUNT`. If/// `CLOSE_COUNT` is 0, the `CloseGuard` removes the span with the/// `id` from the registry, as all `Layers` that might have seen the/// `on_close` notification have processed it. If `CLOSE_COUNT` is/// greater than 0, `CloseGuard` decrements the counter by one and/// _does not_ remove the span from the [`Registry`].///pub(crate) struct CloseGuard<'a> { id: Id, registry: &'a Registry, is_closing: bool,}impl Registry { fn get(&self, id: &Id) -> Option<Ref<'_, DataInner>> { self.spans.get(id_to_idx(id)) } /// Returns a guard which tracks how many `Subscriber`s have /// processed an `on_close` notification via the `CLOSE_COUNT` thread-local. /// For additional details, see [`CloseGuard`]. /// pub(crate) fn start_close(&self, id: Id) -> CloseGuard<'_> { CLOSE_COUNT.with(|count| { let c = count.get(); count.set(c + 1); }); CloseGuard { id, registry: &self, is_closing: false, } }}thread_local! { /// `CLOSE_COUNT` is the thread-local counter used by `CloseGuard` to /// track how many layers have processed the close. /// For additional details, see [`CloseGuard`]. /// static CLOSE_COUNT: Cell<usize> = Cell::new(0);}impl Collect for Registry { fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest { Interest::always() } fn enabled(&self, _: &Metadata<'_>) -> bool { true } #[inline] fn new_span(&self, attrs: &span::Attributes<'_>) -> span::Id { let parent = if attrs.is_root() { None } else if attrs.is_contextual() { self.current_span().id().map(|id| self.clone_span(id)) } else { attrs.parent().map(|id| self.clone_span(id)) }; let id = self .spans // Check out a `DataInner` entry from the pool for the new span. If // there are free entries already allocated in the pool, this will // preferentially reuse one; otherwise, a new `DataInner` is // allocated and added to the pool. .create_with(|data| { data.metadata = attrs.metadata(); data.parent = parent; let refs = data.ref_count.get_mut(); debug_assert_eq!(*refs, 0); *refs = 1; }) .expect("Unable to allocate another span"); idx_to_id(id) } /// This is intentionally not implemented, as recording fields /// on a span is the responsibility of layers atop of this registry. #[inline] fn record(&self, _: &span::Id, _: &span::Record<'_>) {} fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {} /// This is intentionally not implemented, as recording events /// is the responsibility of layers atop of this registry. fn event(&self, _: &Event<'_>) {} fn enter(&self, id: &span::Id) { if self .current_spans .get_or_default() .borrow_mut() .push(id.clone()) { self.clone_span(id); } } fn exit(&self, id: &span::Id) { if let Some(spans) = self.current_spans.get() { if spans.borrow_mut().pop(id) { dispatch::get_default(|dispatch| dispatch.try_close(id.clone())); } } } fn clone_span(&self, id: &span::Id) -> span::Id { let span = self .get(&id) .unwrap_or_else(|| panic!("tried to clone {:?}, but no span exists with that ID", id)); // Like `std::sync::Arc`, adds to the ref count (on clone) don't require // a strong ordering; if we call` clone_span`, the reference count must // always at least 1. The only synchronization necessary is between // calls to `try_close`: we have to ensure that all threads have // dropped their refs to the span before the span is closed. let refs = span.ref_count.fetch_add(1, Ordering::Relaxed); assert!( refs != 0, "tried to clone a span ({:?}) that already closed", id ); id.clone() } fn current_span(&self) -> Current { self.current_spans .get() .and_then(|spans| { let spans = spans.borrow(); let id = spans.current()?; let span = self.get(id)?; Some(Current::new(id.clone(), span.metadata)) }) .unwrap_or_else(Current::none) } /// Decrements the reference count of the span with the given `id`, and /// removes the span if it is zero. /// /// The allocated span slot will be reused when a new span is created. fn try_close(&self, id: span::Id) -> bool { let span = match self.get(&id) { Some(span) => span, None if std::thread::panicking() => return false, None => panic!("tried to drop a ref to {:?}, but no such span exists!", id), }; let refs = span.ref_count.fetch_sub(1, Ordering::Release); if !std::thread::panicking() { assert!(refs < std::usize::MAX, "reference count overflow!"); } if refs > 1 { return false; } // Synchronize if we are actually removing the span (stolen // from std::Arc); this ensures that all other `try_close` calls on // other threads happen-before we actually remove the span. fence(Ordering::Acquire); true }}impl<'a> LookupSpan<'a> for Registry { type Data = Data<'a>; fn span_data(&'a self, id: &Id) -> Option<Self::Data> { let inner = self.get(id)?; Some(Data { inner }) }}// === impl CloseGuard ===impl<'a> CloseGuard<'a> { pub(crate) fn is_closing(&mut self) { self.is_closing = true; }}impl<'a> Drop for CloseGuard<'a> { fn drop(&mut self) { // If this returns with an error, we are already panicking. At // this point, there's nothing we can really do to recover // except by avoiding a double-panic. let _ = CLOSE_COUNT.try_with(|count| { let c = count.get(); // Decrement the count to indicate that _this_ guard's // `on_close` callback has completed. // // Note that we *must* do this before we actually remove the span // from the registry, since dropping the `DataInner` may trigger a // new close, if this span is the last reference to a parent span. count.set(c - 1); // If the current close count is 1, this stack frame is the last // `on_close` call. If the span is closing, it's okay to remove the // span. if c == 1 && self.is_closing { self.registry.spans.clear(id_to_idx(&self.id)); } }); }}// === impl Data ===impl<'a> SpanData<'a> for Data<'a> { fn id(&self) -> Id { idx_to_id(self.inner.key()) } fn metadata(&self) -> &'static Metadata<'static> { (*self).inner.metadata } fn parent(&self) -> Option<&Id> { self.inner.parent.as_ref() } fn extensions(&self) -> Extensions<'_> { Extensions::new(self.inner.extensions.read().expect("Mutex poisoned")) } fn extensions_mut(&self) -> ExtensionsMut<'_> { ExtensionsMut::new(self.inner.extensions.write().expect("Mutex poisoned")) }}// === impl DataInner ===impl Default for DataInner { fn default() -> Self { // Since `DataInner` owns a `&'static Callsite` pointer, we need // something to use as the initial default value for that callsite. // Since we can't access a `DataInner` until it has had actual span data // inserted into it, the null metadata will never actually be accessed. struct NullCallsite; impl tracing_core::callsite::Callsite for NullCallsite { fn set_interest(&self, _: Interest) { unreachable!( "/!\\ Tried to register the null callsite /!\\\n \ This should never have happened and is definitely a bug. \ A `tracing` bug report would be appreciated." ) } fn metadata(&self) -> &Metadata<'_> { unreachable!( "/!\\ Tried to access the null callsite's metadata /!\\\n \ This should never have happened and is definitely a bug. \ A `tracing` bug report would be appreciated." ) } } static NULL_CALLSITE: NullCallsite = NullCallsite; static NULL_METADATA: Metadata<'static> = tracing_core::metadata! { name: "", target: "", level: tracing_core::Level::TRACE, fields: &[], callsite: &NULL_CALLSITE, kind: tracing_core::metadata::Kind::SPAN, }; Self { metadata: &NULL_METADATA, parent: None, ref_count: AtomicUsize::new(0), extensions: RwLock::new(ExtensionsInner::new()), } }}impl Clear for DataInner { /// Clears the span's data in place, dropping the parent's reference count. fn clear(&mut self) { // A span is not considered closed until all of its children have closed. // Therefore, each span's `DataInner` holds a "reference" to the parent // span, keeping the parent span open until all its children have closed. // When we close a span, we must then decrement the parent's ref count // (potentially, allowing it to close, if this child is the last reference // to that span). // We have to actually unpack the option inside the `get_default` // closure, since it is a `FnMut`, but testing that there _is_ a value // here lets us avoid the thread-local access if we don't need the // dispatcher at all. if self.parent.is_some() { // Note that --- because `Layered::try_close` works by calling // `try_close` on the inner subscriber and using the return value to // determine whether to call the `Layer`'s `on_close` callback --- // we must call `try_close` on the entire subscriber stack, rather // than just on the registry. If the registry called `try_close` on // itself directly, the layers wouldn't see the close notification. let subscriber = dispatch::get_default(Dispatch::clone); if let Some(parent) = self.parent.take() { let _ = subscriber.try_close(parent); } } // Clear (but do not deallocate!) the pooled `HashMap` for the span's extensions. self.extensions .get_mut() .unwrap_or_else(|l| { // This function can be called in a `Drop` impl, such as while // panicking, so ignore lock poisoning. l.into_inner() }) .clear(); }}#[cfg(test)]mod tests { use super::Registry; use crate::{registry::LookupSpan, subscribe::Context, Subscribe}; use std::{ collections::HashMap, sync::{Arc, Mutex, Weak}, }; use tracing::{self, collect::with_default}; use tracing_core::{ dispatch, span::{Attributes, Id}, Collect, }; struct AssertionSubscriber; impl<C> Subscribe<C> for AssertionSubscriber where C: Collect + for<'a> LookupSpan<'a>, { fn on_close(&self, id: Id, ctx: Context<'_, C>) { dbg!(format_args!("closing {:?}", id)); assert!(&ctx.span(&id).is_some()); } } #[test] fn single_layer_can_access_closed_span() { let subscriber = AssertionSubscriber.with_collector(Registry::default()); with_default(subscriber, || { let span = tracing::debug_span!("span"); drop(span); }); } #[test] fn multiple_layers_can_access_closed_span() { let subscriber = AssertionSubscriber .and_then(AssertionSubscriber) .with_collector(Registry::default()); with_default(subscriber, || { let span = tracing::debug_span!("span"); drop(span); }); } struct CloseLayer { inner: Arc<Mutex<CloseState>>, } struct CloseHandle { state: Arc<Mutex<CloseState>>, } #[derive(Default)] struct CloseState { open: HashMap<&'static str, Weak<()>>, closed: Vec<(&'static str, Weak<()>)>, } struct SetRemoved(Arc<()>); impl<S> Subscribe<S> for CloseLayer where S: Collect + for<'a> LookupSpan<'a>, { fn new_span(&self, _: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) { let span = ctx.span(id).expect("Missing span; this is a bug"); let mut lock = self.inner.lock().unwrap(); let is_removed = Arc::new(()); assert!( lock.open .insert(span.name(), Arc::downgrade(&is_removed)) .is_none(), "test layer saw multiple spans with the same name, the test is probably messed up" ); let mut extensions = span.extensions_mut(); extensions.insert(SetRemoved(is_removed)); } fn on_close(&self, id: Id, ctx: Context<'_, S>) { let span = if let Some(span) = ctx.span(&id) { span } else { println!( "span {:?} did not exist in `on_close`, are we panicking?", id ); return; }; let name = span.name(); println!("close {} ({:?})", name, id); if let Ok(mut lock) = self.inner.lock() { if let Some(is_removed) = lock.open.remove(name) { assert!(is_removed.upgrade().is_some()); lock.closed.push((name, is_removed)); } } } } impl CloseLayer { fn new() -> (Self, CloseHandle) { let state = Arc::new(Mutex::new(CloseState::default())); ( Self { inner: state.clone(), }, CloseHandle { state }, ) } } impl CloseState { fn is_open(&self, span: &str) -> bool { self.open.contains_key(span) } fn is_closed(&self, span: &str) -> bool { self.closed.iter().any(|(name, _)| name == &span) } } impl CloseHandle { fn assert_closed(&self, span: &str) { let lock = self.state.lock().unwrap(); assert!( lock.is_closed(span), "expected {} to be closed{}", span, if lock.is_open(span) { " (it was still open)" } else { ", but it never existed (is there a problem with the test?)" } ) } fn assert_open(&self, span: &str) { let lock = self.state.lock().unwrap(); assert!( lock.is_open(span), "expected {} to be open{}", span, if lock.is_closed(span) { " (it was still open)" } else { ", but it never existed (is there a problem with the test?)" } ) } fn assert_removed(&self, span: &str) { let lock = self.state.lock().unwrap(); let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) { Some((_, is_removed)) => is_removed, None => panic!( "expected {} to be removed from the registry, but it was not closed {}", span, if lock.is_closed(span) { " (it was still open)" } else { ", but it never existed (is there a problem with the test?)" } ), }; assert!( is_removed.upgrade().is_none(), "expected {} to have been removed from the registry", span ) } fn assert_not_removed(&self, span: &str) { let lock = self.state.lock().unwrap(); let is_removed = match lock.closed.iter().find(|(name, _)| name == &span) { Some((_, is_removed)) => is_removed, None if lock.is_open(span) => return, None => unreachable!(), }; assert!( is_removed.upgrade().is_some(), "expected {} to have been removed from the registry", span ) } #[allow(unused)] // may want this for future tests fn assert_last_closed(&self, span: Option<&str>) { let lock = self.state.lock().unwrap(); let last = lock.closed.last().map(|(span, _)| span); assert_eq!( last, span.as_ref(), "expected {:?} to have closed last", span ); } fn assert_closed_in_order(&self, order: impl AsRef<[&'static str]>) { let lock = self.state.lock().unwrap(); let order = order.as_ref(); for (i, name) in order.iter().enumerate() { assert_eq!( lock.closed.get(i).map(|(span, _)| span), Some(name), "expected close order: {:?}, actual: {:?}", order, lock.closed.iter().map(|(name, _)| name).collect::<Vec<_>>() ); } } } #[test] fn spans_are_removed_from_registry() { let (close_layer, state) = CloseLayer::new(); let subscriber = AssertionSubscriber .and_then(close_layer) .with_collector(Registry::default()); // Create a `Dispatch` (which is internally reference counted) so that // the subscriber lives to the end of the test. Otherwise, if we just // passed the subscriber itself to `with_default`, we could see the span // be dropped when the subscriber itself is dropped, destroying the // registry. let dispatch = dispatch::Dispatch::new(subscriber); dispatch::with_default(&dispatch, || { let span = tracing::debug_span!("span1"); drop(span); let span = tracing::info_span!("span2"); drop(span); }); state.assert_removed("span1"); state.assert_removed("span2"); // Ensure the registry itself outlives the span. drop(dispatch); } #[test] fn spans_are_only_closed_when_the_last_ref_drops() { let (close_layer, state) = CloseLayer::new(); let subscriber = AssertionSubscriber .and_then(close_layer) .with_collector(Registry::default()); // Create a `Dispatch` (which is internally reference counted) so that // the subscriber lives to the end of the test. Otherwise, if we just // passed the subscriber itself to `with_default`, we could see the span // be dropped when the subscriber itself is dropped, destroying the // registry. let dispatch = dispatch::Dispatch::new(subscriber); let span2 = dispatch::with_default(&dispatch, || { let span = tracing::debug_span!("span1"); drop(span); let span2 = tracing::info_span!("span2"); let span2_clone = span2.clone(); drop(span2); span2_clone }); state.assert_removed("span1"); state.assert_not_removed("span2"); drop(span2); state.assert_removed("span1"); // Ensure the registry itself outlives the span. drop(dispatch); } #[test] fn span_enter_guards_are_dropped_out_of_order() { let (close_layer, state) = CloseLayer::new(); let subscriber = AssertionSubscriber .and_then(close_layer) .with_collector(Registry::default()); // Create a `Dispatch` (which is internally reference counted) so that // the subscriber lives to the end of the test. Otherwise, if we just // passed the subscriber itself to `with_default`, we could see the span // be dropped when the subscriber itself is dropped, destroying the // registry. let dispatch = dispatch::Dispatch::new(subscriber); dispatch::with_default(&dispatch, || { let span1 = tracing::debug_span!("span1"); let span2 = tracing::info_span!("span2"); let enter1 = span1.enter(); let enter2 = span2.enter(); drop(enter1); drop(span1); state.assert_removed("span1"); state.assert_not_removed("span2"); drop(enter2); state.assert_not_removed("span2"); drop(span2); state.assert_removed("span1"); state.assert_removed("span2"); }); } #[test] fn child_closes_parent() { // This test asserts that if a parent span's handle is dropped before // a child span's handle, the parent will remain open until child // closes, and will then be closed. let (close_layer, state) = CloseLayer::new(); let subscriber = close_layer.with_collector(Registry::default()); let dispatch = dispatch::Dispatch::new(subscriber); dispatch::with_default(&dispatch, || { let span1 = tracing::info_span!("parent"); let span2 = tracing::info_span!(parent: &span1, "child"); state.assert_open("parent"); state.assert_open("child"); drop(span1); state.assert_open("parent"); state.assert_open("child"); drop(span2); state.assert_closed("parent"); state.assert_closed("child"); }); } #[test] fn child_closes_grandparent() { // This test asserts that, when a span is kept open by a child which // is *itself* kept open by a child, closing the grandchild will close // both the parent *and* the grandparent. let (close_layer, state) = CloseLayer::new(); let subscriber = close_layer.with_collector(Registry::default()); let dispatch = dispatch::Dispatch::new(subscriber); dispatch::with_default(&dispatch, || { let span1 = tracing::info_span!("grandparent"); let span2 = tracing::info_span!(parent: &span1, "parent"); let span3 = tracing::info_span!(parent: &span2, "child"); state.assert_open("grandparent"); state.assert_open("parent"); state.assert_open("child"); drop(span1); drop(span2); state.assert_open("grandparent"); state.assert_open("parent"); state.assert_open("child"); drop(span3); state.assert_closed_in_order(&["child", "parent", "grandparent"]); }); }}
Currently, the way I run intraconv
is like this:
for crate in tracing*; do cargo intraconv $crate/**/*.rs -c $(echo $crate | tr - _) -a; done
It would be nice to have this built-in. In particular, this
-/// [non_blocking]: ./non_blocking/index.html
+/// [non_blocking]: non_blocking
Similar to #17. I'd like these links:
tracing/src/lib.rs://! [fmt]: https://doc.rust-lang.org/std/fmt/#usage
tracing/src/lib.rs://! [`libstd`]: https://doc.rust-lang.org/std/index.html
tracing/src/lib.rs://! [`liballoc`]: https://doc.rust-lang.org/alloc/index.html
to be turned into these:
tracing/src/lib.rs://! [fmt]: std::fmt#usage
tracing/src/lib.rs://! [`libstd`]: std
tracing/src/lib.rs://! [`liballoc`]: alloc
In an ideal world:
/nightly
, /beta, and /stable would be stripped (e.g. https://doc.rust-lang.org/nightly/std/primitive.str.html)For example macros can be suffixed with !
, functions and methods with ()
and primitives can be prefixed primitive@
.
Feel free to close this as wontfix.
Before:
/// <strong>Note</strong>: The fields associated with a span are part of its
/// <a href="../struct.Metadata.html"><code>Metadata</code></a>.
/// The <a href="../struct.Metadata.html"><code>Metadata</code></a>. describing a particular
/// span is constructed statically when the span is created and cannot be extended later to
After:
/// <strong>Note</strong>: The fields associated with a span are part of its
///
/// [`Metadata`](super::Metadata). The [Metadata](super::Metadata) describing a particular
/// span is constructed statically when the span is created and cannot be extended later to
The extra blank line may not be necessary depending on the markdown parser, I haven't tested.
/home/joshua/src/rust/tracing/tracing-subscriber/src/registry/sharded.rs
========================================================================
39: "/// [slab]: https://docs.rs/crate/sharded-slab/"
"/// [slab]: crate"
This can't be converted automatically, /crate/sharded-slab
is not the target of any intra-doc link.
Not sure how hard this is to implement - maybe not so bad since the HTML file has primitive
in the name?
/home/joshua/src/rust/rust-clippy/clippy_lints/src/empty_enum.rs
================================================================
16: " /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)"
" /// For further information visit [never type documentation](std::never)"
Right now you can ignore links globally:
[ignore]
"name" = [ "link 1" ]
and per-file:
["tracing-core/src/lib.rs"]
"`downcast_ref`" = [ "#method.downcast_ref" ]
but not per crate. It would be nice to be able to say "ignore links to String
, but only in the core
crate".
I'm not sure how to fit that in to the existing syntax - I think we might have hemmed ourselves in by getting too clever with the keys. Maybe something like this?
[[crate]]
name = "core"
"String" = "../../std/str/struct.String.html"
That means you can't ignore a name
link I think, but I'm not sure what other syntax intra-conv could use.
Haven't tried to make an MVCE yet, but if you run intraconv
on tracing-subscriber, it turns /// [
on_exit]: #method.on_exit
into SubscriberExt
when it should use Layer
instead. This is https://github.com/tokio-rs/tracing/blob/e9b6645f0c7cff6e4164b9ecd3d290939ffd77d9/tracing-subscriber/src/layer.rs#L250
This is a regression from yesterday.
tracing-appender/src/inner.rs
=============================
1: "use std::io::{BufWriter, Write};
"
"use std::io::{BufWriter, Write};
"
2: "
"
"
"
3: "
"
"
"
4: "
"
"
"
diff --git a/tracing-appender/src/inner.rs b/tracing-appender/src/inner.rs
index f1e0fe0..6ade116 100644
--- a/tracing-appender/src/inner.rs
+++ b/tracing-appender/src/inner.rs
@@ -1,96 +1,768 @@
use std::io::{BufWriter, Write};
+
+
+
+
+
+
+
I was about to report a bug that ignoring links didn't work, then realized that I hadn't passed --ignore-file
. It would be nice for this to default to intraconv.toml
so I don't have to remember it (and gracefully ignore the file if it doesn't exist).
At least, I think that's the issue. Not sure why tracing::Event
was removed but not the others.
-//! [`tracing::Collector`]: https://docs.rs/tracing/latest/tracing/trait.Collect.html
-//! [`Collect`]: https://docs.rs/tracing/latest/tracing/trait.Collect.html
-//! [`tracing::Event`]: https://docs.rs/tracing/latest/tracing/struct.Event.html
+//! [`tracing::Collector`]: tracing::Collect
+//! [`Collect`]: tracing::Collect
It would be nice for
[ignore]
"xyz" = ["abc"]
to match both [xyz]: abc
and [`xyz`]: abc
. Otherwise you have to make two entries for the same link.
I changed my mind after #13 ๐ I liked the way the links looked before, I'd rather change them by hand than have type@
everywhere. Sorry to be a pain!
This just happened after the changes for #13. -
is before the change, +
is after.
-//! [`Layer` type]: Layer
-//! [`Layer` trait]: super::layer::Layer
+//! [`Layer` type]: struct.Layer.html
+//! [`Layer` trait]: ../layer/trait.Layer.html
tracing/tracing-serde/src/lib.rs
================================
8: "//! [docs-badge]: https://docs.rs/tracing-serde/badge.svg"
"//! [docs-badge]: tracing_serde"
$ rg '\[.*\]: \.\./.*'
tracing-core/src/event.rs
20:/// [span]: ../span
21:/// [fields]: ../field
tracing/src/span.rs
403: /// [metadata]: ../metadata
428: /// [metadata]: ../metadata
452: /// [metadata]: ../metadata
$ rg '\[.*\]: (trait|struct|enum|fn)\..*\.html*'
tracing-log/src/lib.rs
376:/// [`normalized_metadata`]: trait.NormalizeEvent.html#normalized_metadata
[`tracing`][tracing]
could just be [`tracing`]
.
tracing/tracing/src/lib.rs
==========================
24: "//! [msrv]: #supported-rust-versions"
"//! [msrv]: MacroCallsite#supported-rust-versions"
This is wrong and it should stay empty.
I have an idea for how to fix this and I'm interested in working on this myself.
Currently, this does nothing:
[ignore]
"`handle_alloc_error`" = ["../../alloc/alloc/fn.handle_alloc_error.html"]
because intra-conv is looking at the whole line:
[src/config_file.rs:80] name = " /// [`handle_alloc_error`]: "
[src/config_file.rs:80] value = "../../alloc/alloc/fn.handle_alloc_error.html"
core: alloc/global.rs
=====
89: " /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html"
" /// [`handle_alloc_error`]: super::super::alloc::alloc::handle_alloc_error()"
-/// [fmt]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html
+/// [fmt]: https:::::docs.rs::tracing-subscriber::latest::tracing_subscriber::fmt
This is documentation on a struct, which is on a separate page from the module index.
1463: "/// [intrinsics]: index.html#intrinsic-variables"
"/// [intrinsics]: #intrinsic-variables"
Instead it should link to self#intrinsic-variables
.
-//! [non_blocking]: ./non_blocking/index.html
+//! [non_blocking]: .::non_blocking
I'd like to turn this link:
/// [`Span`]: https://docs.rs/tracing-core/latest/tracing_core/span/index.html
into this one:
/// [`Span`]: tracing_code::span
I think this should be fairly easy to add: if the URL starts with https://docs.rs
, strip the host and first 2 path segments, then treat it like a normal link.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.