-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlib.rs
More file actions
129 lines (117 loc) · 5.31 KB
/
Copy pathlib.rs
File metadata and controls
129 lines (117 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! The diffr plugin contract in Rust. `wit/plugin.wit` in the diffr
//! repository is the contract; this crate is its one Rust form, shared by
//! every plugin whether diffr compiles it in or runs it as a WASM component.
//!
//! - [`types`] holds the contract's records: the file entry, each side's
//! flat preorder region list with parent ids and text, and the moves. They
//! are generated from `wit/plugin.wit` itself, so there is one definition
//! of each, and a plugin hands diffr the same records natively and as a
//! component.
//! - [`Plugin`] is the one trait every plugin implements: `new`, which makes
//! it from its options, `queries`, then `classify` and `mutate`, taking
//! and returning exactly those records.
//! - [`host`] holds what diffr gives every plugin: `git`.
//! - [`export!`] makes a plugin the `plugin` resource a component exports
//! when the crate is built for `wasm32-wasip2`, and
//! otherwise exposes its native registration for the host to collect.
//! The same source builds both ways.
//!
//! Plugins reason about regions with the same code:
//!
//! - [`tree`] rebuilds a side's list as a tree ([`tree::sides`], which the
//! SDK calls on the way in so a plugin is handed [`Pairing`] of [`Source`]
//! rather than the flat records) and holds the helpers for reading trees ([`walk`], [`OtherSide`], [`one_sided`],
//! [`docstring_of`], and the rest).
//! - [`apply`] carries moves out. diffr carries every plugin's moves out with
//! it, so [`Draft`], which carries a plugin's moves out on a copy as it
//! makes them, and [`apply::Fresh`], which predicts fresh ids, give a
//! plugin exactly the ids diffr will.
pub mod apply;
pub mod draft;
pub mod host;
#[cfg(not(target_arch = "wasm32"))]
pub mod native;
pub mod tree;
pub mod types;
pub use anyhow;
pub use draft::Draft;
use serde::de::DeserializeOwned;
pub use tree::{
before_and_after_ids, docstring_of, has_tag, is_fold, line_count, one_sided, path_to,
siblings_of, sides_with_other_ids, walk, walk_mut, Node, OtherSide, Pairing, Region, Source,
};
pub use types::{
Annotation, FileEntry, FileRef, FileSides, FileStatus, Move, Position, QuerySource, Range,
Side, Span, Visibility, ROOT,
};
/// A diffr plugin: the `plugin` resource of `wit/plugin.wit`. diffr makes one
/// with [`Plugin::new`] when it builds its pipeline, before any file, and
/// calls that one instance for every file of the run.
pub trait Plugin: Sized {
/// The plugin's options, deserialized from its bundled or external config
/// entry: a JSON object, validated against the options schema in
/// `plugin.toml` and filled with its defaults.
type Options: DeserializeOwned;
/// Make the plugin from its options. An error, like options that do not
/// deserialize, is a setup error naming the plugin.
fn new(options: Self::Options) -> anyhow::Result<Self>;
/// Named query text, collected once during setup and compiled by diffr.
fn queries(&self) -> anyhow::Result<Vec<QuerySource>> {
Ok(Vec::new())
}
/// Tags to add to the file's manifest entry before it is diffed. A
/// plugin that does not classify returns none.
fn classify(&self, file: &FileEntry) -> anyhow::Result<Vec<String>>;
/// The moves that shape how the diffed file starts out. `sides` are the
/// sides the file has, already rebuilt as trees.
fn mutate(&self, file: &FileEntry, sides: &Pairing<Source>) -> anyhow::Result<Vec<Move>>;
/// Deferred labels for stable region IDs, after all initial mutations.
fn enrich(
&self,
_file: &FileEntry,
_sides: &Pairing<Source>,
) -> anyhow::Result<Vec<Annotation>> {
Ok(Vec::new())
}
}
/// The contract generated from `wit/plugin.wit`. Its records are plain Rust
/// and compile for every target, so [`types`] re-exports them and a plugin
/// works with the generated records wherever it runs; only the `export!`
/// macro this generates is wasm-specific, and [`export!`] calls it there.
#[doc(hidden)]
pub mod bindings {
wit_bindgen::generate!({
path: "wit",
world: "plugin",
pub_export_macro: true,
default_bindings_module: "diffr_plugin_sdk::bindings",
additional_derives: [PartialEq, Eq],
});
}
#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
pub mod guest;
/// Export a [`Plugin`] as the component's `plugin` resource when the crate
/// is built for `wasm32`: the resource's `new` deserializes the options
/// string into [`Plugin::Options`] and calls [`Plugin::new`], and its
/// `classify` and `mutate` call the instance. Built for anything else it
/// exposes its name and constructor as `DIFFR_PLUGIN` for the host registry.
#[macro_export]
macro_rules! export {
($name:literal, $plugin:ty) => {
#[cfg(not(target_arch = "wasm32"))]
#[doc(hidden)]
pub static DIFFR_PLUGIN: $crate::native::Registration = $crate::native::Registration {
name: $name,
create: $crate::native::create::<$plugin>,
};
#[cfg(target_arch = "wasm32")]
const _: () = {
struct DiffrPluginExport;
impl $crate::bindings::exports::diffr::plugin::guest::Guest for DiffrPluginExport {
type Plugin = $crate::guest::Instance<$plugin>;
}
$crate::bindings::export!(DiffrPluginExport with_types_in $crate::bindings);
};
};
}