Code Monkey home page Code Monkey logo

cargo-intraconv's Issues

Deletes attributes

-//!
-#![doc(html_root_url = "https://docs.rs/tracing-appender/0.1.1")]
+

Add a way to ignore links

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).

-a removes all whitespace

$ 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"]);        });    }}

Run on all crates in the workspace

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

  • Runs on all crates in the workspace
  • Sets the crate name appropriately
  • Runs on all files within a crate

Convert doc.rust-lang.org to intra-doc links

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:

[stretch] convert <a href=""> to intra-doc links

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.

docs.rs/crate/x is treated as if crate/ is a crate

/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.

Intraconv shouldn't convert links to primitives

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)"

Ignore links per-crate?

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.

Regression: adds lots of new whitespace

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};
+
+
+
+
+
+
+

Read `intraconv.toml` by default

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).

Redundant links are not removed if they were originally HTTP links

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

Missing links again :(

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

Some links are not caught

$ 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

Properly detect blocks

tracing/tracing/src/lib.rs
==========================

   24:  "//! [msrv]: #supported-rust-versions"
        "//! [msrv]: MacroCallsite#supported-rust-versions"

This is wrong and it should stay empty.

Ignore file compares the whole line, not the link

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()"

Don't replace links starting with http(s)

-/// [fmt]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html
+/// [fmt]: https:::::docs.rs::tracing-subscriber::latest::tracing_subscriber::fmt

`index.html` should link to `self`, not the current page

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.

Support for docs.rs links

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.