Add GetSpanContents engine call (#12439)

# Description
This allows plugins to view the source code of spans.

Requested by @ayax79 for implementing `polars ls`. Note that this won't
really help you find the location of the span. I'm planning to add
another engine call that will return information more similar to what
shows up in the miette diagnostics, with filename / line number / some
context, but I'll want to refactor some of the existing logic to make
that happen, so it was easier to just do this first. I hope this is
enough to at least have something somewhat useful show up for `polars
ls`.

# User-Facing Changes
- Example plugin: added `example view span` command

# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting
- [ ] Add to plugin protocol reference
This commit is contained in:
Devyn Cairns
2024-04-09 07:02:17 -07:00
committed by GitHub
parent 9a2a6ab52c
commit 00b3a07efe
8 changed files with 124 additions and 2 deletions

View File

@ -16,10 +16,12 @@ pub use two::Two;
mod config;
mod disable_gc;
mod env;
mod view_span;
pub use config::Config;
pub use disable_gc::DisableGc;
pub use env::Env;
pub use view_span::ViewSpan;
// Stream demos
mod collect_external;

View File

@ -0,0 +1,58 @@
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
use nu_protocol::{Category, Example, LabeledError, Signature, Type, Value};
use crate::ExamplePlugin;
/// `<value> | example view span`
pub struct ViewSpan;
impl SimplePluginCommand for ViewSpan {
type Plugin = ExamplePlugin;
fn name(&self) -> &str {
"example view span"
}
fn usage(&self) -> &str {
"Example command for looking up the contents of a parser span"
}
fn extra_usage(&self) -> &str {
"Shows the original source code of the expression that generated the value passed as input."
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.input_output_type(Type::Any, Type::String)
.category(Category::Experimental)
}
fn search_terms(&self) -> Vec<&str> {
vec!["example"]
}
fn examples(&self) -> Vec<Example> {
vec![Example {
example: "('hello ' ++ 'world') | example view span",
description: "Show the source code of the expression that generated a value",
result: Some(Value::test_string("'hello ' ++ 'world'")),
}]
}
fn run(
&self,
_plugin: &ExamplePlugin,
engine: &EngineInterface,
call: &EvaluatedCall,
input: &Value,
) -> Result<Value, LabeledError> {
let contents = engine.get_span_contents(input.span())?;
Ok(Value::string(String::from_utf8_lossy(&contents), call.head))
}
}
#[test]
fn test_examples() -> Result<(), nu_protocol::ShellError> {
use nu_plugin_test_support::PluginTest;
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&ViewSpan)
}

View File

@ -21,6 +21,7 @@ impl Plugin for ExamplePlugin {
// Engine interface demos
Box::new(Config),
Box::new(Env),
Box::new(ViewSpan),
Box::new(DisableGc),
// Stream demos
Box::new(CollectExternal),