mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 15:39:06 +01:00
Add some comments (#1225)
This commit is contained in:
parent
3adf52b1c4
commit
b32eceffb3
@ -304,6 +304,7 @@ impl serde::de::Error for ShellError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ShellError {
|
impl ShellError {
|
||||||
|
/// An error that describes a mismatch between the given type and the expected type
|
||||||
pub fn type_error(
|
pub fn type_error(
|
||||||
expected: impl Into<String>,
|
expected: impl Into<String>,
|
||||||
actual: Spanned<impl Into<String>>,
|
actual: Spanned<impl Into<String>>,
|
||||||
|
@ -5,6 +5,7 @@ use nu_source::{b, span_for_spanned_list, DebugDocBuilder, HasFallibleSpan, Pret
|
|||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A PathMember that has yet to be spanned so that it can be used in later processing
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||||
pub enum UnspannedPathMember {
|
pub enum UnspannedPathMember {
|
||||||
String(String),
|
String(String),
|
||||||
@ -12,6 +13,7 @@ pub enum UnspannedPathMember {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UnspannedPathMember {
|
impl UnspannedPathMember {
|
||||||
|
/// Add the span information and get a full PathMember
|
||||||
pub fn into_path_member(self, span: impl Into<Span>) -> PathMember {
|
pub fn into_path_member(self, span: impl Into<Span>) -> PathMember {
|
||||||
PathMember {
|
PathMember {
|
||||||
unspanned: self,
|
unspanned: self,
|
||||||
@ -20,6 +22,7 @@ impl UnspannedPathMember {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A basic piece of a ColumnPath, which describes the steps to take through a table to arrive a cell, row, or inner table
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||||
pub struct PathMember {
|
pub struct PathMember {
|
||||||
pub unspanned: UnspannedPathMember,
|
pub unspanned: UnspannedPathMember,
|
||||||
@ -27,6 +30,7 @@ pub struct PathMember {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for &PathMember {
|
impl PrettyDebug for &PathMember {
|
||||||
|
/// Gets the PathMember ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match &self.unspanned {
|
match &self.unspanned {
|
||||||
UnspannedPathMember::String(string) => b::primitive(format!("{:?}", string)),
|
UnspannedPathMember::String(string) => b::primitive(format!("{:?}", string)),
|
||||||
@ -35,6 +39,10 @@ impl PrettyDebug for &PathMember {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The fundamental path primitive to descrive how to navigate through a table to get to a sub-item. A path member can be either a word or a number. Words/strings are taken to mean
|
||||||
|
/// a column name, and numbers are the row number. Taken together they describe which column or row to narrow to in order to get data.
|
||||||
|
///
|
||||||
|
/// Rows must follow column names, they can't come first. eg) `foo.1` is valid where `1.foo` is not.
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Hash, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Getters, Clone, new,
|
Debug, Hash, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Getters, Clone, new,
|
||||||
)]
|
)]
|
||||||
@ -44,16 +52,19 @@ pub struct ColumnPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnPath {
|
impl ColumnPath {
|
||||||
|
/// Iterate over the members of the column path
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &PathMember> {
|
pub fn iter(&self) -> impl Iterator<Item = &PathMember> {
|
||||||
self.members.iter()
|
self.members.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the last member and a slice of the remaining members
|
||||||
pub fn split_last(&self) -> Option<(&PathMember, &[PathMember])> {
|
pub fn split_last(&self) -> Option<(&PathMember, &[PathMember])> {
|
||||||
self.members.split_last()
|
self.members.split_last()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for ColumnPath {
|
impl PrettyDebug for ColumnPath {
|
||||||
|
/// Gets the ColumnPath ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
let members: Vec<DebugDocBuilder> =
|
let members: Vec<DebugDocBuilder> =
|
||||||
self.members.iter().map(|member| member.pretty()).collect();
|
self.members.iter().map(|member| member.pretty()).collect();
|
||||||
@ -68,6 +79,7 @@ impl PrettyDebug for ColumnPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HasFallibleSpan for ColumnPath {
|
impl HasFallibleSpan for ColumnPath {
|
||||||
|
/// Creates a span that will cover the column path, if possible
|
||||||
fn maybe_span(&self) -> Option<Span> {
|
fn maybe_span(&self) -> Option<Span> {
|
||||||
if self.members.is_empty() {
|
if self.members.is_empty() {
|
||||||
None
|
None
|
||||||
@ -78,15 +90,18 @@ impl HasFallibleSpan for ColumnPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PathMember {
|
impl PathMember {
|
||||||
|
/// Create a string path member
|
||||||
pub fn string(string: impl Into<String>, span: impl Into<Span>) -> PathMember {
|
pub fn string(string: impl Into<String>, span: impl Into<Span>) -> PathMember {
|
||||||
UnspannedPathMember::String(string.into()).into_path_member(span)
|
UnspannedPathMember::String(string.into()).into_path_member(span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a numeric path member
|
||||||
pub fn int(int: impl Into<BigInt>, span: impl Into<Span>) -> PathMember {
|
pub fn int(int: impl Into<BigInt>, span: impl Into<Span>) -> PathMember {
|
||||||
UnspannedPathMember::Int(int.into()).into_path_member(span)
|
UnspannedPathMember::Int(int.into()).into_path_member(span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prepares a list of "sounds like" matches for the string you're trying to find
|
||||||
pub fn did_you_mean(obj_source: &Value, field_tried: &PathMember) -> Option<Vec<(usize, String)>> {
|
pub fn did_you_mean(obj_source: &Value, field_tried: &PathMember) -> Option<Vec<(usize, String)>> {
|
||||||
let field_tried = match &field_tried.unspanned {
|
let field_tried = match &field_tried.unspanned {
|
||||||
UnspannedPathMember::String(string) => string.clone(),
|
UnspannedPathMember::String(string) => string.clone(),
|
||||||
|
@ -8,6 +8,7 @@ use nu_source::TaggedItem;
|
|||||||
impl std::convert::TryFrom<&Value> for i64 {
|
impl std::convert::TryFrom<&Value> for i64 {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
|
/// Convert to an i64 integer, if possible
|
||||||
fn try_from(value: &Value) -> Result<i64, ShellError> {
|
fn try_from(value: &Value) -> Result<i64, ShellError> {
|
||||||
match &value.value {
|
match &value.value {
|
||||||
UntaggedValue::Primitive(Primitive::Int(int)) => {
|
UntaggedValue::Primitive(Primitive::Int(int)) => {
|
||||||
@ -21,6 +22,7 @@ impl std::convert::TryFrom<&Value> for i64 {
|
|||||||
impl std::convert::TryFrom<&Value> for String {
|
impl std::convert::TryFrom<&Value> for String {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
|
/// Convert to a string, if possible
|
||||||
fn try_from(value: &Value) -> Result<String, ShellError> {
|
fn try_from(value: &Value) -> Result<String, ShellError> {
|
||||||
match &value.value {
|
match &value.value {
|
||||||
UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
UntaggedValue::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
||||||
@ -32,6 +34,7 @@ impl std::convert::TryFrom<&Value> for String {
|
|||||||
impl std::convert::TryFrom<&Value> for Vec<u8> {
|
impl std::convert::TryFrom<&Value> for Vec<u8> {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
|
/// Convert to a u8 vec, if possible
|
||||||
fn try_from(value: &Value) -> Result<Vec<u8>, ShellError> {
|
fn try_from(value: &Value) -> Result<Vec<u8>, ShellError> {
|
||||||
match &value.value {
|
match &value.value {
|
||||||
UntaggedValue::Primitive(Primitive::Binary(b)) => Ok(b.clone()),
|
UntaggedValue::Primitive(Primitive::Binary(b)) => Ok(b.clone()),
|
||||||
@ -43,6 +46,7 @@ impl std::convert::TryFrom<&Value> for Vec<u8> {
|
|||||||
impl<'a> std::convert::TryFrom<&'a Value> for &'a Dictionary {
|
impl<'a> std::convert::TryFrom<&'a Value> for &'a Dictionary {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
|
/// Convert to a dictionary, if possible
|
||||||
fn try_from(value: &'a Value) -> Result<&'a Dictionary, ShellError> {
|
fn try_from(value: &'a Value) -> Result<&'a Dictionary, ShellError> {
|
||||||
match &value.value {
|
match &value.value {
|
||||||
UntaggedValue::Row(d) => Ok(d),
|
UntaggedValue::Row(d) => Ok(d),
|
||||||
|
@ -4,12 +4,14 @@ use crate::value::{UntaggedValue, Value};
|
|||||||
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
use nu_source::{b, DebugDocBuilder, PrettyDebug};
|
||||||
|
|
||||||
impl PrettyDebug for &Value {
|
impl PrettyDebug for &Value {
|
||||||
|
/// Get a borrowed Value ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
PrettyDebug::pretty(*self)
|
PrettyDebug::pretty(*self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for Value {
|
impl PrettyDebug for Value {
|
||||||
|
/// Get a Value ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match &self.value {
|
match &self.value {
|
||||||
UntaggedValue::Primitive(p) => p.pretty(),
|
UntaggedValue::Primitive(p) => p.pretty(),
|
||||||
@ -24,6 +26,7 @@ impl PrettyDebug for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyType for Primitive {
|
impl PrettyType for Primitive {
|
||||||
|
/// Find the type of the Value and prepare it for pretty-printing
|
||||||
fn pretty_type(&self) -> DebugDocBuilder {
|
fn pretty_type(&self) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Nothing => ty("nothing"),
|
Primitive::Nothing => ty("nothing"),
|
||||||
@ -47,6 +50,7 @@ impl PrettyType for Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for Primitive {
|
impl PrettyDebug for Primitive {
|
||||||
|
/// Get a Primitive value ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Nothing => b::primitive("nothing"),
|
Primitive::Nothing => b::primitive("nothing"),
|
||||||
|
@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::cmp::{Ord, Ordering, PartialOrd};
|
use std::cmp::{Ord, Ordering, PartialOrd};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
/// A dictionary that can hold a mapping from names to Values
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Getters, new)]
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, Getters, new)]
|
||||||
pub struct Dictionary {
|
pub struct Dictionary {
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
@ -17,6 +18,7 @@ pub struct Dictionary {
|
|||||||
|
|
||||||
#[allow(clippy::derive_hash_xor_eq)]
|
#[allow(clippy::derive_hash_xor_eq)]
|
||||||
impl Hash for Dictionary {
|
impl Hash for Dictionary {
|
||||||
|
/// Create the hash function to allow the Hash trait for dictionaries
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
let mut entries = self.entries.clone();
|
let mut entries = self.entries.clone();
|
||||||
entries.sort_keys();
|
entries.sort_keys();
|
||||||
@ -26,6 +28,7 @@ impl Hash for Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Dictionary {
|
impl PartialOrd for Dictionary {
|
||||||
|
/// Compare two dictionaries for sort ordering
|
||||||
fn partial_cmp(&self, other: &Dictionary) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Dictionary) -> Option<Ordering> {
|
||||||
let this: Vec<&String> = self.entries.keys().collect();
|
let this: Vec<&String> = self.entries.keys().collect();
|
||||||
let that: Vec<&String> = other.entries.keys().collect();
|
let that: Vec<&String> = other.entries.keys().collect();
|
||||||
@ -42,6 +45,7 @@ impl PartialOrd for Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Dictionary {
|
impl Ord for Dictionary {
|
||||||
|
/// Compare two dictionaries for ordering
|
||||||
fn cmp(&self, other: &Dictionary) -> Ordering {
|
fn cmp(&self, other: &Dictionary) -> Ordering {
|
||||||
let this: Vec<&String> = self.entries.keys().collect();
|
let this: Vec<&String> = self.entries.keys().collect();
|
||||||
let that: Vec<&String> = other.entries.keys().collect();
|
let that: Vec<&String> = other.entries.keys().collect();
|
||||||
@ -58,6 +62,7 @@ impl Ord for Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<Value> for Dictionary {
|
impl PartialEq<Value> for Dictionary {
|
||||||
|
/// Test a dictionary against a Value for equality
|
||||||
fn eq(&self, other: &Value) -> bool {
|
fn eq(&self, other: &Value) -> bool {
|
||||||
match &other.value {
|
match &other.value {
|
||||||
UntaggedValue::Row(d) => self == d,
|
UntaggedValue::Row(d) => self == d,
|
||||||
@ -66,6 +71,7 @@ impl PartialEq<Value> for Dictionary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A key-value pair specifically meant to be used in debug and pretty-printing
|
||||||
#[derive(Debug, new)]
|
#[derive(Debug, new)]
|
||||||
struct DebugEntry<'a> {
|
struct DebugEntry<'a> {
|
||||||
key: &'a str,
|
key: &'a str,
|
||||||
@ -73,12 +79,14 @@ struct DebugEntry<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrettyDebug for DebugEntry<'a> {
|
impl<'a> PrettyDebug for DebugEntry<'a> {
|
||||||
|
/// Build the the information to pretty-print the DebugEntry
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
(b::key(self.key.to_string()) + b::equals() + self.value.pretty().into_value()).group()
|
(b::key(self.key.to_string()) + b::equals() + self.value.pretty().into_value()).group()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyDebug for Dictionary {
|
impl PrettyDebug for Dictionary {
|
||||||
|
/// Get a Dictionary ready to be pretty-printed
|
||||||
fn pretty(&self) -> DebugDocBuilder {
|
fn pretty(&self) -> DebugDocBuilder {
|
||||||
b::delimit(
|
b::delimit(
|
||||||
"(",
|
"(",
|
||||||
@ -94,6 +102,7 @@ impl PrettyDebug for Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<IndexMap<String, Value>> for Dictionary {
|
impl From<IndexMap<String, Value>> for Dictionary {
|
||||||
|
/// Create a dictionary from a map of strings to Values
|
||||||
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
||||||
let mut out = IndexMap::default();
|
let mut out = IndexMap::default();
|
||||||
|
|
||||||
@ -106,6 +115,7 @@ impl From<IndexMap<String, Value>> for Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Dictionary {
|
impl Dictionary {
|
||||||
|
/// Find the matching Value for a given key, if possible. If not, return a Primitive::Nothing
|
||||||
pub fn get_data(&self, desc: &str) -> MaybeOwned<'_, Value> {
|
pub fn get_data(&self, desc: &str) -> MaybeOwned<'_, Value> {
|
||||||
match self.entries.get(desc) {
|
match self.entries.get(desc) {
|
||||||
Some(v) => MaybeOwned::Borrowed(v),
|
Some(v) => MaybeOwned::Borrowed(v),
|
||||||
@ -115,10 +125,12 @@ impl Dictionary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate the keys in the Dictionary
|
||||||
pub fn keys(&self) -> impl Iterator<Item = &String> {
|
pub fn keys(&self) -> impl Iterator<Item = &String> {
|
||||||
self.entries.keys()
|
self.entries.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the matching Value for a key, if possible
|
||||||
pub fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value> {
|
pub fn get_data_by_key(&self, name: Spanned<&str>) -> Option<Value> {
|
||||||
let result = self
|
let result = self
|
||||||
.entries
|
.entries
|
||||||
@ -134,6 +146,7 @@ impl Dictionary {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mutable entry that matches a key, if possible
|
||||||
pub fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> {
|
pub fn get_mut_data_by_key(&mut self, name: &str) -> Option<&mut Value> {
|
||||||
match self
|
match self
|
||||||
.entries
|
.entries
|
||||||
@ -145,11 +158,13 @@ impl Dictionary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a new key/value pair into the dictionary
|
||||||
pub fn insert_data_at_key(&mut self, name: &str, value: Value) {
|
pub fn insert_data_at_key(&mut self, name: &str, value: Value) {
|
||||||
self.entries.insert(name.to_string(), value);
|
self.entries.insert(name.to_string(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A helper to help create dictionaries for you. It has the ability to insert values into the dictionary while maintaining the tags that need to be applied to the individual members
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TaggedDictBuilder {
|
pub struct TaggedDictBuilder {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
@ -157,6 +172,7 @@ pub struct TaggedDictBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedDictBuilder {
|
impl TaggedDictBuilder {
|
||||||
|
/// Create a new builder
|
||||||
pub fn new(tag: impl Into<Tag>) -> TaggedDictBuilder {
|
pub fn new(tag: impl Into<Tag>) -> TaggedDictBuilder {
|
||||||
TaggedDictBuilder {
|
TaggedDictBuilder {
|
||||||
tag: tag.into(),
|
tag: tag.into(),
|
||||||
@ -164,6 +180,7 @@ impl TaggedDictBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build the contents of the builder into a Value
|
||||||
pub fn build(tag: impl Into<Tag>, block: impl FnOnce(&mut TaggedDictBuilder)) -> Value {
|
pub fn build(tag: impl Into<Tag>, block: impl FnOnce(&mut TaggedDictBuilder)) -> Value {
|
||||||
let mut builder = TaggedDictBuilder::new(tag);
|
let mut builder = TaggedDictBuilder::new(tag);
|
||||||
block(&mut builder);
|
block(&mut builder);
|
||||||
|
@ -226,6 +226,7 @@ impl History {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input.
|
||||||
pub async fn cli() -> Result<(), Box<dyn Error>> {
|
pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
let mut context = Context::basic()?;
|
let mut context = Context::basic()?;
|
||||||
|
|
||||||
@ -560,6 +561,7 @@ enum LineResult {
|
|||||||
Break,
|
Break,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process the line by parsing the text to turn it into commands, classify those commands so that we understand what is being called in the pipeline, and then run this pipeline
|
||||||
async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context) -> LineResult {
|
async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context) -> LineResult {
|
||||||
match &readline {
|
match &readline {
|
||||||
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
|
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
|
||||||
|
Loading…
Reference in New Issue
Block a user