mirror of
https://git.vulpinecitrus.info/Lymkwi/estrus-navigator.git
synced 2024-12-03 15:26:35 +00:00
Implement display of identifiers
- Implement identifier types and display - Move all of it into its own submodule - Parse CLI args as the list of identifiers to fetch
This commit is contained in:
parent
1dac97b2dc
commit
6d2b3ead16
|
@ -11,3 +11,6 @@ license = "ACSL"
|
|||
reqwest = { version = "0.11.22", features = ["default-tls", "json", "gzip"] }
|
||||
serde = { version = "1.0.190", features = ["derive"] }
|
||||
tokio = { version = "1.33.0", features = ["rt-multi-thread", "macros", "net"] }
|
||||
|
||||
[[bin]]
|
||||
name = "estrus"
|
||||
|
|
4
README.md
Normal file
4
README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
Estrus Elixir Navigator
|
||||
===
|
||||
|
||||
CLI navigator for the Elixir linux project.
|
182
src/ident.rs
Normal file
182
src/ident.rs
Normal file
|
@ -0,0 +1,182 @@
|
|||
//! Structures structuring identifiers
|
||||
//!
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter::FromIterator;
|
||||
use std::marker::PhantomData as Phantom;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::de::{self, Deserializer, Visitor};
|
||||
|
||||
use reqwest::Client;
|
||||
|
||||
/// Response to an query on the Elixir API
|
||||
///
|
||||
/// Holds the deserialized response to a query to the elixir API regarding definitions, references,
|
||||
/// and documentation of an identifier.
|
||||
#[derive(serde::Deserialize, Debug, Default)]
|
||||
pub struct Response {
|
||||
/// List of definitions
|
||||
definitions: Vec<Definition>,
|
||||
/// List of references
|
||||
references: Vec<Reference>,
|
||||
/// List of positions in the documentation
|
||||
documentations: Vec<Documentation>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Retrieve definitions of the identifier
|
||||
pub fn get_definitions(&self) -> &[Definition] {
|
||||
&self.definitions
|
||||
}
|
||||
|
||||
/// Retrieve references of the identifier
|
||||
pub fn get_references(&self) -> &[Reference] {
|
||||
&self.references
|
||||
}
|
||||
|
||||
/// Retrieve documentation for the identifier
|
||||
pub fn get_documentations(&self) -> &[Documentation] {
|
||||
&self.documentations
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
/// Different possible types of ifier Definitions
|
||||
pub enum DefinitionType {
|
||||
#[serde(rename(deserialize = "prototype"))]
|
||||
Prototype,
|
||||
#[serde(rename(deserialize = "member"))]
|
||||
Member,
|
||||
#[serde(rename(deserialize = "function"))]
|
||||
Function,
|
||||
#[serde(rename(deserialize = "enumerator"))]
|
||||
Enumerator,
|
||||
#[serde(rename(deserialize = "struct"))]
|
||||
Struct,
|
||||
#[serde(rename(deserialize = "variable"))]
|
||||
Variable,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DefinitionType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Definition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"[{:^9}] {}:{}",
|
||||
self.deftype.to_string(),
|
||||
self.path.to_str().unwrap_or("<???>"),
|
||||
self.line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub struct Definition {
|
||||
path: PathBuf,
|
||||
line: u32,
|
||||
#[serde(rename(deserialize = "type"))]
|
||||
deftype: DefinitionType,
|
||||
}
|
||||
|
||||
fn comma_separated<'de, V, T, D>(deserializer: D) -> Result<V, D::Error>
|
||||
where
|
||||
V: FromIterator<T>,
|
||||
T: FromStr,
|
||||
T::Err: Display,
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct CommaSeparated<V, T>(Phantom<V>, Phantom<T>);
|
||||
|
||||
impl<'de, V, T> Visitor<'de> for CommaSeparated<V, T>
|
||||
where
|
||||
V: FromIterator<T>,
|
||||
T: FromStr,
|
||||
T::Err: Display,
|
||||
{
|
||||
type Value = V;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("string containing comma-separated elements")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
s.split(',')
|
||||
.map(FromStr::from_str)
|
||||
.collect::<Result<Self::Value, _>>()
|
||||
.map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = CommaSeparated(Phantom, Phantom);
|
||||
deserializer.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub struct Reference {
|
||||
path: PathBuf,
|
||||
#[serde(deserialize_with = "comma_separated")]
|
||||
line: Vec<u32>,
|
||||
//#[serde(rename(serialize = "type"))]
|
||||
//reftype: Option<()>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Reference {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}",
|
||||
self.path.to_str().unwrap_or("<???>"),
|
||||
self.line
|
||||
.iter()
|
||||
.map(u32::to_string)
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub struct Documentation {
|
||||
path: PathBuf,
|
||||
#[serde(deserialize_with = "comma_separated")]
|
||||
line: Vec<u32>,
|
||||
//#[serde(rename(serialize = "type"))]
|
||||
//doctype: Option<()>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Documentation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}:{}",
|
||||
self.path.to_str().unwrap_or("<???>"),
|
||||
self.line
|
||||
.iter()
|
||||
.map(u32::to_string)
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn find(ident: &str) -> Response {
|
||||
let client = Client::new();
|
||||
let res = client
|
||||
.get(format!(
|
||||
"https://elixir.bootlin.com/api/ident/linux/{ident}?version=latest"
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.expect("No future failure");
|
||||
res.json::<Response>().await.expect("No failure")
|
||||
}
|
82
src/main.rs
82
src/main.rs
|
@ -1,60 +1,40 @@
|
|||
//! Main module for the project
|
||||
//!
|
||||
|
||||
use std::path::PathBuf;
|
||||
#![deny(clippy::perf)]
|
||||
#![deny(clippy::pedantic)]
|
||||
#![deny(clippy::complexity)]
|
||||
#![deny(clippy::correctness)]
|
||||
|
||||
use reqwest::Client;
|
||||
use std::env::args;
|
||||
|
||||
/// Response to an Ident query on the Elixir API
|
||||
///
|
||||
/// Holds the deserialized response to a query to the elixir API regarding definitions, references,
|
||||
/// and documentation of an identifier.
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct IdentResponse {
|
||||
/// List of definitions
|
||||
definitions: Vec<IdentDefinition>,
|
||||
/// List of references
|
||||
references: Vec<IdentReference>,
|
||||
/// List of positions in the documentation
|
||||
documentations: Vec<IdentDocumentation>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
/// Different possible types of Identifier Definitions
|
||||
enum IdentDefinitionType {
|
||||
Prototype,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct IdentDefinition {
|
||||
path: PathBuf,
|
||||
line: u32,
|
||||
deftype: IdentDefinitionType,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct IdentReference {
|
||||
path: PathBuf,
|
||||
line: u32,
|
||||
reftype: Option<()>
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct IdentDocumentation {
|
||||
path: PathBuf,
|
||||
line: u32,
|
||||
doctype: Option<()>
|
||||
}
|
||||
|
||||
async fn find_ident(ident: &str) -> IdentResponse {
|
||||
let client = Client::new();
|
||||
let res = client.get(format!("https://elixir.bootlin.com/api/ident/linux/{ident}?version=latest"))
|
||||
.send()
|
||||
.await.expect("No future failure");
|
||||
res.json::<IdentResponse>().await.expect("No failure")
|
||||
}
|
||||
mod ident;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("{:?}", find_ident("clear_page_erms").await)
|
||||
let arg_list = args().skip(1);
|
||||
for arg in arg_list {
|
||||
println!("{:=^60}", format!(" {arg} "));
|
||||
show_one_ident(&arg).await;
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
println!("")
|
||||
}
|
||||
}
|
||||
|
||||
async fn show_one_ident(ident: &str) {
|
||||
let id_resp = ident::find(ident).await;
|
||||
println!("Definitions:");
|
||||
for defs in id_resp.get_definitions() {
|
||||
println!(" - {defs}");
|
||||
}
|
||||
|
||||
println!("References:");
|
||||
for refs in id_resp.get_references() {
|
||||
println!(" - {refs}");
|
||||
}
|
||||
|
||||
println!("Documentation:");
|
||||
for docs in id_resp.get_documentations() {
|
||||
println!(" - {docs}");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue