forked from extern/nushell
feat: add attribute selection to nu_plugion_selector (#3519)
This allows the user to specify for example selector a -t href to downselect based on an attribute Co-authored-by: ahkrr <alexhk@protonmail.com>
This commit is contained in:
parent
a5c14ba7d4
commit
9dbb3e80fe
@ -10,7 +10,7 @@ version = "0.31.1"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nipper = "0.1.8"
|
nipper = "0.1.9"
|
||||||
nu-errors = { version = "0.31.1", path = "../nu-errors" }
|
nu-errors = { version = "0.31.1", path = "../nu-errors" }
|
||||||
nu-plugin = { version = "0.31.1", path = "../nu-plugin" }
|
nu-plugin = { version = "0.31.1", path = "../nu-plugin" }
|
||||||
nu-protocol = { version = "0.31.1", path = "../nu-protocol" }
|
nu-protocol = { version = "0.31.1", path = "../nu-protocol" }
|
||||||
|
@ -3,7 +3,6 @@ use nu_plugin::Plugin;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value,
|
CallInfo, Primitive, ReturnSuccess, ReturnValue, Signature, SyntaxShape, UntaggedValue, Value,
|
||||||
};
|
};
|
||||||
use nu_source::TaggedItem;
|
|
||||||
|
|
||||||
use crate::{selector::begin_selector_query, Selector};
|
use crate::{selector::begin_selector_query, Selector};
|
||||||
|
|
||||||
@ -13,6 +12,12 @@ impl Plugin for Selector {
|
|||||||
.desc("execute selector query on html/web")
|
.desc("execute selector query on html/web")
|
||||||
.required("query", SyntaxShape::String, "selector query")
|
.required("query", SyntaxShape::String, "selector query")
|
||||||
.switch("as_html", "return the query output as html", Some('a'))
|
.switch("as_html", "return the query output as html", Some('a'))
|
||||||
|
.named(
|
||||||
|
"attribute",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"downselect based on the given attribute",
|
||||||
|
Some('t'),
|
||||||
|
)
|
||||||
.filter())
|
.filter())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +34,9 @@ impl Plugin for Selector {
|
|||||||
self.query = query.as_string()?;
|
self.query = query.as_string()?;
|
||||||
self.tag = tag;
|
self.tag = tag;
|
||||||
self.as_html = call_info.args.has("as_html");
|
self.as_html = call_info.args.has("as_html");
|
||||||
|
if call_info.args.has("attribute") {
|
||||||
|
self.attribute = call_info.args.expect_get("attribute")?.convert_to_string();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
@ -38,12 +46,10 @@ impl Plugin for Selector {
|
|||||||
Value {
|
Value {
|
||||||
value: UntaggedValue::Primitive(Primitive::String(s)),
|
value: UntaggedValue::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => Ok(
|
} => Ok(begin_selector_query(s, &self)
|
||||||
begin_selector_query(s, (*self.query).tagged(&self.tag), self.as_html)
|
.into_iter()
|
||||||
.into_iter()
|
.map(ReturnSuccess::value)
|
||||||
.map(ReturnSuccess::value)
|
.collect()),
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
Value { tag, .. } => Err(ShellError::labeled_error_with_secondary(
|
Value { tag, .. } => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected text from pipeline",
|
"Expected text from pipeline",
|
||||||
"requires text input",
|
"requires text input",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use nipper::Document;
|
use nipper::Document;
|
||||||
use nu_protocol::{value::StringExt, Value};
|
use nu_protocol::{value::StringExt, Value};
|
||||||
use nu_source::{Tag, Tagged};
|
use nu_source::Tag;
|
||||||
|
|
||||||
pub struct Selector {
|
pub struct Selector {
|
||||||
pub query: String,
|
pub query: String,
|
||||||
pub tag: Tag,
|
pub tag: Tag,
|
||||||
pub as_html: bool,
|
pub as_html: bool,
|
||||||
|
pub attribute: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Selector {
|
impl Selector {
|
||||||
@ -14,6 +15,7 @@ impl Selector {
|
|||||||
query: String::new(),
|
query: String::new(),
|
||||||
tag: Tag::unknown(),
|
tag: Tag::unknown(),
|
||||||
as_html: false,
|
as_html: false,
|
||||||
|
attribute: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,42 +26,54 @@ impl Default for Selector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_selector_query(input: String, query: Tagged<&str>, as_html: bool) -> Vec<Value> {
|
pub fn begin_selector_query(input_html: String, selector: &Selector) -> Vec<Value> {
|
||||||
execute_selector_query(input, query.item.to_string(), query.tag(), as_html)
|
match selector.attribute.is_empty() {
|
||||||
|
true => execute_selector_query(
|
||||||
|
input_html.as_str(),
|
||||||
|
selector.query.as_str(),
|
||||||
|
selector.as_html,
|
||||||
|
),
|
||||||
|
false => execute_selector_query_with_attribute(
|
||||||
|
input_html.as_str(),
|
||||||
|
selector.query.as_str(),
|
||||||
|
selector.attribute.as_str(),
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_selector_query(
|
fn execute_selector_query_with_attribute(
|
||||||
input_string: String,
|
input_string: &str,
|
||||||
query_string: String,
|
query_string: &str,
|
||||||
tag: impl Into<Tag>,
|
attribute: &str,
|
||||||
as_html: bool,
|
|
||||||
) -> Vec<Value> {
|
) -> Vec<Value> {
|
||||||
let _tag = tag.into();
|
let doc = Document::from(input_string);
|
||||||
let mut ret = vec![];
|
|
||||||
let doc = Document::from(&input_string);
|
|
||||||
|
|
||||||
// How to internally iterate
|
doc.select(&query_string)
|
||||||
// doc.nip("tr.athing").iter().for_each(|athing| {
|
.iter()
|
||||||
// let title = format!("{}", athing.select(".title a").text().to_string());
|
.map(|selection| {
|
||||||
// let href = athing
|
selection
|
||||||
// .select(".storylink")
|
.attr_or(attribute, "")
|
||||||
// .attr("href")
|
.to_string()
|
||||||
// .unwrap()
|
.to_string_value_create_tag()
|
||||||
// .to_string();
|
})
|
||||||
// let title_url = format!("{} - {}\n", title, href);
|
.collect()
|
||||||
// ret.push(title_url.to_string_value_create_tag());
|
}
|
||||||
// });
|
|
||||||
|
|
||||||
if as_html {
|
fn execute_selector_query(input_string: &str, query_string: &str, as_html: bool) -> Vec<Value> {
|
||||||
doc.nip(&query_string).iter().for_each(|athing| {
|
let doc = Document::from(input_string);
|
||||||
ret.push(athing.html().to_string().to_string_value_create_tag());
|
|
||||||
});
|
match as_html {
|
||||||
} else {
|
true => doc
|
||||||
doc.nip(&query_string).iter().for_each(|athing| {
|
.select(&query_string)
|
||||||
ret.push(athing.text().to_string().to_string_value_create_tag());
|
.iter()
|
||||||
});
|
.map(|selection| selection.html().to_string().to_string_value_create_tag())
|
||||||
|
.collect(),
|
||||||
|
false => doc
|
||||||
|
.select(&query_string)
|
||||||
|
.iter()
|
||||||
|
.map(|selection| selection.text().to_string().to_string_value_create_tag())
|
||||||
|
.collect(),
|
||||||
}
|
}
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user