mirror of
https://github.com/nushell/nushell.git
synced 2024-12-24 07:59:21 +01:00
view span & view files commands (#7989)
# Description This PR does the following: 1. Adds a new command called `view span` - which shows what is at the location of the span parameters 2. Adds a new command called `view` - which just lists all the `view` commands. 3. Renames `view-source` to `view source`. 4. Adds a new command called `view files` - which shows you what files are loaded into nushell's EngineState memory. 5. Added a `Category::Debug` and put these commands (and others) into it. (`inspect` needs to be added to it, but it's not landed yet) Spans are important to nushell. One of their uses is to show where errors are. For instance, in this example, the leader lines pointing to parts of the command line are able to point to `10`, `/`, and `"bob"` because each of those items have a span. ``` > 10 / "bob" Error: nu::parser::unsupported_operation (link) × Types mismatched for operation. ╭─[entry #8:1:1] 1 │ 10 / "bob" · ─┬ ┬ ──┬── · │ │ ╰── string · │ ╰── doesn't support these values. · ╰── int ╰──── help: Change int or string to be the right types and try again. ``` # Examples ## view span Example: ``` > $env.config | get keybindings | first | debug -r ... bunch of stuff span: Span { start: 68065, end: 68090, }, }, ], span: Span { start: 68050, end: 68101, }, }, ], span: Span { start: 67927, end: 68108, }, } ``` To view the last span: ``` > view span 67927 68108 { name: clear_everything modifier: control keycode: char_l mode: emacs event: [ { send: clearscrollback } ] } ``` > To view the 2nd to last span: ``` view span 68065 68090 { send: clearscrollback } ``` > To view the 3rd to last span: ``` view span 68050 68101 [ { send: clearscrollback } ] ``` ## view files ``` > view files ╭────┬───────────────────────────────────────────────────────┬────────┬────────┬───────╮ │ # │ filename │ start │ end │ size │ ├────┼───────────────────────────────────────────────────────┼────────┼────────┼───────┤ │ 0 │ source │ 0 │ 2 │ 2 │ │ 1 │ Host Environment Variables │ 2 │ 6034 │ 6032 │ │ 2 │ C:\Users\a_username\AppData\Roaming\nushell\plugin.nu │ 6034 │ 31236 │ 25202 │ │ 3 │ C:\Users\a_username\AppData\Roaming\nushell\env.nu │ 31236 │ 44961 │ 13725 │ │ 4 │ C:\Users\a_username\AppData\Roaming\nushell\config.nu │ 44961 │ 76134 │ 31173 │ │ 5 │ defs.nu │ 76134 │ 91944 │ 15810 │ │ 6 │ prompt\oh-my.nu │ 91944 │ 111523 │ 19579 │ │ 7 │ weather\get-weather.nu │ 111523 │ 125556 │ 14033 │ │ 8 │ .zoxide.nu │ 125556 │ 127504 │ 1948 │ │ 9 │ source │ 127504 │ 127561 │ 57 │ │ 10 │ entry #1 │ 127561 │ 127585 │ 24 │ │ 11 │ entry #2 │ 127585 │ 127595 │ 10 │ ╰────┴───────────────────────────────────────────────────────┴────────┴────────┴───────╯ ``` `entry #x` will be each command you type in the repl (i think). so, it may be good to filter those out sometimes. ``` > view files | where filename !~ entry ╭───┬───────────────────────────────────────────────────────┬────────┬────────┬───────╮ │ # │ filename │ start │ end │ size │ ├───┼───────────────────────────────────────────────────────┼────────┼────────┼───────┤ │ 0 │ source │ 0 │ 2 │ 2 │ │ 1 │ Host Environment Variables │ 2 │ 6034 │ 6032 │ │ 2 │ C:\Users\a_username\AppData\Roaming\nushell\plugin.nu │ 6034 │ 31236 │ 25202 │ │ 3 │ C:\Users\a_username\AppData\Roaming\nushell\env.nu │ 31236 │ 44961 │ 13725 │ │ 4 │ C:\Users\a_username\AppData\Roaming\nushell\config.nu │ 44961 │ 76134 │ 31173 │ │ 5 │ defs.nu │ 76134 │ 91944 │ 15810 │ │ 6 │ prompt\oh-my.nu │ 91944 │ 111523 │ 19579 │ │ 7 │ weather\get-weather.nu │ 111523 │ 125556 │ 14033 │ │ 8 │ .zoxide.nu │ 125556 │ 127504 │ 1948 │ │ 9 │ source │ 127504 │ 127561 │ 57 │ ╰───┴───────────────────────────────────────────────────────┴────────┴────────┴───────╯ ``` # User-Facing Changes I renamed `view-source` to `view source` just to make a group of commands. No functionality has changed in `view source`. # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
parent
659d890ecf
commit
023e244958
@ -24,7 +24,7 @@ impl Command for Debug {
|
|||||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||||
(Type::Any, Type::String),
|
(Type::Any, Type::String),
|
||||||
])
|
])
|
||||||
.category(Category::Core)
|
.category(Category::Debug)
|
||||||
.switch("raw", "Prints the raw value representation", Some('r'))
|
.switch("raw", "Prints the raw value representation", Some('r'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,8 +473,11 @@ pub fn create_default_context() -> EngineState {
|
|||||||
|
|
||||||
// Experimental
|
// Experimental
|
||||||
bind_command! {
|
bind_command! {
|
||||||
ViewSource,
|
|
||||||
IsAdmin,
|
IsAdmin,
|
||||||
|
View,
|
||||||
|
ViewFiles,
|
||||||
|
ViewSource,
|
||||||
|
ViewSpan,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
mod is_admin;
|
mod is_admin;
|
||||||
|
mod view;
|
||||||
|
mod view_files;
|
||||||
mod view_source;
|
mod view_source;
|
||||||
|
mod view_span;
|
||||||
|
|
||||||
pub use is_admin::IsAdmin;
|
pub use is_admin::IsAdmin;
|
||||||
|
pub use view::View;
|
||||||
|
pub use view_files::ViewFiles;
|
||||||
pub use view_source::ViewSource;
|
pub use view_source::ViewSource;
|
||||||
|
pub use view_span::ViewSpan;
|
||||||
|
49
crates/nu-command/src/experimental/view.rs
Normal file
49
crates/nu-command/src/experimental/view.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use nu_engine::get_full_help;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack},
|
||||||
|
Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct View;
|
||||||
|
|
||||||
|
impl Command for View {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"view"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("view")
|
||||||
|
.category(Category::Debug)
|
||||||
|
.input_output_types(vec![(Type::Nothing, Type::String)])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Various commands for viewing debug information"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
Ok(Value::String {
|
||||||
|
val: get_full_help(
|
||||||
|
&View.signature(),
|
||||||
|
&View.examples(),
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
self.is_parser_keyword(),
|
||||||
|
),
|
||||||
|
span: call.head,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
|
}
|
||||||
|
}
|
70
crates/nu-command/src/experimental/view_files.rs
Normal file
70
crates/nu-command/src/experimental/view_files.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ViewFiles;
|
||||||
|
|
||||||
|
impl Command for ViewFiles {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"view files"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"View the files registered in nushell's EngineState memory"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"These are files parsed and loaded at runtime."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("view files")
|
||||||
|
.input_output_types(vec![(Type::Nothing, Type::String)])
|
||||||
|
.category(Category::Debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let mut records = vec![];
|
||||||
|
|
||||||
|
for (file, start, end) in engine_state.files() {
|
||||||
|
records.push(Value::Record {
|
||||||
|
cols: vec![
|
||||||
|
"filename".to_string(),
|
||||||
|
"start".to_string(),
|
||||||
|
"end".to_string(),
|
||||||
|
"size".to_string(),
|
||||||
|
],
|
||||||
|
vals: vec![
|
||||||
|
Value::string(file, call.head),
|
||||||
|
Value::int(*start as i64, call.head),
|
||||||
|
Value::int(*end as i64, call.head),
|
||||||
|
Value::int(*end as i64 - *start as i64, call.head),
|
||||||
|
],
|
||||||
|
span: call.head,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::List {
|
||||||
|
vals: records,
|
||||||
|
span: call.head,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "View the files registered in nushell's EngineState memory",
|
||||||
|
example: r#"view files"#,
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ pub struct ViewSource;
|
|||||||
|
|
||||||
impl Command for ViewSource {
|
impl Command for ViewSource {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"view-source"
|
"view source"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
@ -20,10 +20,10 @@ impl Command for ViewSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("view-source")
|
Signature::build("view source")
|
||||||
.input_output_types(vec![(Type::Nothing, Type::String)])
|
.input_output_types(vec![(Type::Nothing, Type::String)])
|
||||||
.required("item", SyntaxShape::Any, "name or block to view")
|
.required("item", SyntaxShape::Any, "name or block to view")
|
||||||
.category(Category::Core)
|
.category(Category::Debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -166,27 +166,27 @@ impl Command for ViewSource {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "View the source of a code block",
|
description: "View the source of a code block",
|
||||||
example: r#"let abc = { echo 'hi' }; view-source $abc"#,
|
example: r#"let abc = { echo 'hi' }; view source $abc"#,
|
||||||
result: Some(Value::test_string("{ echo 'hi' }")),
|
result: Some(Value::test_string("{ echo 'hi' }")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "View the source of a custom command",
|
description: "View the source of a custom command",
|
||||||
example: r#"def hi [] { echo 'Hi!' }; view-source hi"#,
|
example: r#"def hi [] { echo 'Hi!' }; view source hi"#,
|
||||||
result: Some(Value::test_string("{ echo 'Hi!' }")),
|
result: Some(Value::test_string("{ echo 'Hi!' }")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "View the source of a custom command, which participates in the caller environment",
|
description: "View the source of a custom command, which participates in the caller environment",
|
||||||
example: r#"def-env foo [] { let-env BAR = 'BAZ' }; view-source foo"#,
|
example: r#"def-env foo [] { let-env BAR = 'BAZ' }; view source foo"#,
|
||||||
result: Some(Value::test_string("{ let-env BAR = 'BAZ' }")),
|
result: Some(Value::test_string("{ let-env BAR = 'BAZ' }")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "View the source of a module",
|
description: "View the source of a module",
|
||||||
example: r#"module mod-foo { export-env { let-env FOO_ENV = 'BAZ' } }; view-source mod-foo"#,
|
example: r#"module mod-foo { export-env { let-env FOO_ENV = 'BAZ' } }; view source mod-foo"#,
|
||||||
result: Some(Value::test_string(" export-env { let-env FOO_ENV = 'BAZ' }")),
|
result: Some(Value::test_string(" export-env { let-env FOO_ENV = 'BAZ' }")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "View the source of an alias",
|
description: "View the source of an alias",
|
||||||
example: r#"alias hello = echo hi; view-source hello"#,
|
example: r#"alias hello = echo hi; view source hello"#,
|
||||||
result: Some(Value::test_string("echo hi")),
|
result: Some(Value::test_string("echo hi")),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
68
crates/nu-command/src/experimental/view_span.rs
Normal file
68
crates/nu-command/src/experimental/view_span.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Spanned,
|
||||||
|
SyntaxShape, Type, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ViewSpan;
|
||||||
|
|
||||||
|
impl Command for ViewSpan {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"view span"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"View the contents of a span"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"This command is meant for debugging purposes.\nIt allows you to view the contents of nushell spans.\nOne way to get spans is to pipe something into 'debug --raw'.\nThen you can use the Span { start, end } values as the start and end values for this command."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("view span")
|
||||||
|
.input_output_types(vec![(Type::Nothing, Type::String)])
|
||||||
|
.required("start", SyntaxShape::Int, "start of the span")
|
||||||
|
.required("end", SyntaxShape::Int, "end of the span")
|
||||||
|
.category(Category::Debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let start_span: Spanned<usize> = call.req(engine_state, stack, 0)?;
|
||||||
|
let end_span: Spanned<usize> = call.req(engine_state, stack, 1)?;
|
||||||
|
|
||||||
|
if start_span.item < end_span.item {
|
||||||
|
let bin_contents =
|
||||||
|
engine_state.get_span_contents(&Span::new(start_span.item, end_span.item));
|
||||||
|
Ok(
|
||||||
|
Value::string(String::from_utf8_lossy(bin_contents), call.head)
|
||||||
|
.into_pipeline_data(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(ShellError::GenericError(
|
||||||
|
"Cannot view span".to_string(),
|
||||||
|
"this start and end does not correspond to a viewable value".to_string(),
|
||||||
|
Some(call.head),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "View the source of a span. 1 and 2 are just example values. Use the return of debug -r to get the actual values",
|
||||||
|
example: r#"some | pipeline | or | variable | debug -r; view span 1 2"#,
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -40,61 +40,63 @@ pub struct PositionalArg {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum Category {
|
pub enum Category {
|
||||||
Default,
|
|
||||||
Conversions,
|
|
||||||
Core,
|
|
||||||
Bits,
|
Bits,
|
||||||
Bytes,
|
Bytes,
|
||||||
|
Chart,
|
||||||
|
Conversions,
|
||||||
|
Core,
|
||||||
|
Custom(String),
|
||||||
Date,
|
Date,
|
||||||
|
Debug,
|
||||||
|
Default,
|
||||||
|
Deprecated,
|
||||||
Env,
|
Env,
|
||||||
Experimental,
|
Experimental,
|
||||||
FileSystem,
|
FileSystem,
|
||||||
Filters,
|
Filters,
|
||||||
Formats,
|
Formats,
|
||||||
|
Generators,
|
||||||
|
Hash,
|
||||||
Math,
|
Math,
|
||||||
Misc,
|
Misc,
|
||||||
Network,
|
Network,
|
||||||
Random,
|
|
||||||
Platform,
|
Platform,
|
||||||
|
Random,
|
||||||
Shells,
|
Shells,
|
||||||
Strings,
|
Strings,
|
||||||
System,
|
System,
|
||||||
Viewers,
|
Viewers,
|
||||||
Hash,
|
|
||||||
Generators,
|
|
||||||
Chart,
|
|
||||||
Custom(String),
|
|
||||||
Deprecated,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Category {
|
impl std::fmt::Display for Category {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let msg = match self {
|
let msg = match self {
|
||||||
Category::Default => "default",
|
Category::Bits => "bits",
|
||||||
|
Category::Bytes => "bytes",
|
||||||
|
Category::Chart => "chart",
|
||||||
Category::Conversions => "conversions",
|
Category::Conversions => "conversions",
|
||||||
Category::Core => "core",
|
Category::Core => "core",
|
||||||
|
Category::Custom(name) => name,
|
||||||
Category::Date => "date",
|
Category::Date => "date",
|
||||||
|
Category::Debug => "debug",
|
||||||
|
Category::Default => "default",
|
||||||
|
Category::Deprecated => "deprecated",
|
||||||
Category::Env => "env",
|
Category::Env => "env",
|
||||||
Category::Experimental => "experimental",
|
Category::Experimental => "experimental",
|
||||||
Category::FileSystem => "filesystem",
|
Category::FileSystem => "filesystem",
|
||||||
Category::Filters => "filters",
|
Category::Filters => "filters",
|
||||||
Category::Formats => "formats",
|
Category::Formats => "formats",
|
||||||
|
Category::Generators => "generators",
|
||||||
|
Category::Hash => "hash",
|
||||||
Category::Math => "math",
|
Category::Math => "math",
|
||||||
Category::Misc => "misc",
|
Category::Misc => "misc",
|
||||||
Category::Network => "network",
|
Category::Network => "network",
|
||||||
Category::Random => "random",
|
|
||||||
Category::Platform => "platform",
|
Category::Platform => "platform",
|
||||||
|
Category::Random => "random",
|
||||||
Category::Shells => "shells",
|
Category::Shells => "shells",
|
||||||
Category::Strings => "strings",
|
Category::Strings => "strings",
|
||||||
Category::System => "system",
|
Category::System => "system",
|
||||||
Category::Viewers => "viewers",
|
Category::Viewers => "viewers",
|
||||||
Category::Hash => "hash",
|
|
||||||
Category::Generators => "generators",
|
|
||||||
Category::Chart => "chart",
|
|
||||||
Category::Custom(name) => name,
|
|
||||||
Category::Deprecated => "deprecated",
|
|
||||||
Category::Bytes => "bytes",
|
|
||||||
Category::Bits => "bits",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "{msg}")
|
write!(f, "{msg}")
|
||||||
|
Loading…
Reference in New Issue
Block a user