1972 lines · 65.6 KB · Rust
RawDownload
//! This module handles parsing a `git-config` file. Generally speaking, you//! want to use a higher abstraction such as [`GitConfig`] unless you have some//! explicit reason to work with events instead.//!//! The general workflow for interacting with this is to use one of the//! `parse_from_*` function variants. These will return a [`Parser`] on success,//! which can be converted into an [`Event`] iterator. The [`Parser`] also has//! additional methods for accessing leading comments or events by section.//!//! [`GitConfig`]: crate::file::GitConfig use std::{borrow::Cow, convert::TryFrom, fmt::Display, hash::Hash, io::Read, iter::FusedIterator, path::Path}; use nom::{    branch::alt,    bytes::complete::{escaped, tag, take_till, take_while},    character::{        complete::{char, none_of, one_of},        is_space,    },    combinator::{map, opt},    error::{Error as NomError, ErrorKind},    multi::{many0, many1},    sequence::delimited,    IResult,}; /// Syntactic events that occurs in the config. Despite all these variants/// holding a [`Cow`] instead over a simple reference, the parser will only emit/// borrowed `Cow` variants.////// The `Cow` smart pointer is used here for ease of inserting events in a/// middle of an Event iterator. This is used, for example, in the [`GitConfig`]/// struct when adding values.////// [`Cow`]: std::borrow::Cow/// [`GitConfig`]: crate::file::GitConfig#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]pub enum Event<'a> {    /// A comment with a comment tag and the comment itself. Note that the    /// comment itself may contain additional whitespace and comment markers    /// at the beginning.    Comment(ParsedComment<'a>),    /// A section header containing the section name and a subsection, if it    /// exists.    SectionHeader(ParsedSectionHeader<'a>),    /// A name to a value in a section.    Key(Key<'a>),    /// A completed value. This may be any string, including the empty string,    /// if an implicit boolean value is used. Note that these values may contain    /// spaces and any special character. This value is also unprocessed, so it    /// it may contain double quotes that should be replaced.    Value(Cow<'a, [u8]>),    /// Represents any token used to signify a new line character. On Unix    /// platforms, this is typically just `\n`, but can be any valid newline    /// sequence. Multiple newlines (such as `\n\n`) will be merged as a single    /// newline event.    Newline(Cow<'a, str>),    /// Any value that isn't completed. This occurs when the value is continued    /// onto the next line. A Newline event is guaranteed after, followed by    /// either a ValueDone, a Whitespace, or another ValueNotDone.    ValueNotDone(Cow<'a, [u8]>),    /// The last line of a value which was continued onto another line.    ValueDone(Cow<'a, [u8]>),    /// A continuous section of insignificant whitespace. Values with internal    /// spaces will not be separated by this event.    Whitespace(Cow<'a, str>),    /// This event is emitted when the parser counters a valid `=` character    /// separating the key and value. This event is necessary as it eliminates    /// the ambiguity for whitespace events between a key and value event.    KeyValueSeparator,} impl Event<'_> {    /// Generates a byte representation of the value. This should be used when    /// non-UTF-8 sequences are present or a UTF-8 representation can't be    /// guaranteed.    #[must_use]    pub fn to_vec(&self) -> Vec<u8> {        self.into()    }     /// Coerces into an owned instance. This differs from the standard [`clone`]    /// implementation as calling clone will _not_ copy the borrowed variant,    /// while this method will. In other words:    ///    /// | Borrow type | `.clone()` | `to_owned()` |    /// | ----------- | ---------- | ------------ |    /// | Borrowed    | Borrowed   | Owned        |    /// | Owned       | Owned      | Owned        |    ///    /// This can be most effectively seen by the differing lifetimes between the    /// two. This method guarantees a `'static` lifetime, while `clone` does    /// not.    ///    /// [`clone`]: Self::clone    #[must_use]    pub fn to_owned(&self) -> Event<'static> {        match self {            Event::Comment(e) => Event::Comment(e.to_owned()),            Event::SectionHeader(e) => Event::SectionHeader(e.to_owned()),            Event::Key(e) => Event::Key(e.to_owned()),            Event::Value(e) => Event::Value(Cow::Owned(e.clone().into_owned())),            Event::ValueNotDone(e) => Event::ValueNotDone(Cow::Owned(e.clone().into_owned())),            Event::ValueDone(e) => Event::ValueDone(Cow::Owned(e.clone().into_owned())),            Event::Newline(e) => Event::Newline(Cow::Owned(e.clone().into_owned())),            Event::Whitespace(e) => Event::Whitespace(Cow::Owned(e.clone().into_owned())),            Event::KeyValueSeparator => Event::KeyValueSeparator,        }    }} impl Display for Event<'_> {    /// Note that this is a best-effort attempt at printing an `Event`. If    /// there are non UTF-8 values in your config, this will _NOT_ render    /// as read.    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        match self {            Self::Value(e) | Self::ValueNotDone(e) | Self::ValueDone(e) => match std::str::from_utf8(e) {                Ok(e) => e.fmt(f),                Err(_) => write!(f, "{:02x?}", e),            },            Self::Comment(e) => e.fmt(f),            Self::SectionHeader(e) => e.fmt(f),            Self::Key(e) => e.fmt(f),            Self::Newline(e) | Self::Whitespace(e) => e.fmt(f),            Self::KeyValueSeparator => write!(f, "="),        }    }} impl From<Event<'_>> for Vec<u8> {    fn from(event: Event) -> Self {        event.into()    }} impl From<&Event<'_>> for Vec<u8> {    fn from(event: &Event) -> Self {        match event {            Event::Value(e) | Event::ValueNotDone(e) | Event::ValueDone(e) => e.to_vec(),            Event::Comment(e) => e.into(),            Event::SectionHeader(e) => e.into(),            Event::Key(e) => e.0.as_bytes().to_vec(),            Event::Newline(e) | Event::Whitespace(e) => e.as_bytes().to_vec(),            Event::KeyValueSeparator => vec![b'='],        }    }} /// A parsed section containing the header and the section events.#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedSection<'a> {    /// The section name and subsection name, if any.    pub section_header: ParsedSectionHeader<'a>,    /// The syntactic events found in this section.    pub events: Vec<Event<'a>>,} impl ParsedSection<'_> {    /// Coerces into an owned instance. This differs from the standard [`clone`]    /// implementation as calling clone will _not_ copy the borrowed variant,    /// while this method will. In other words:    ///    /// | Borrow type | `.clone()` | `to_owned()` |    /// | ----------- | ---------- | ------------ |    /// | Borrowed    | Borrowed   | Owned        |    /// | Owned       | Owned      | Owned        |    ///    /// This can be most effectively seen by the differing lifetimes between the    /// two. This method guarantees a `'static` lifetime, while `clone` does    /// not.    ///    /// [`clone`]: Self::clone    #[must_use]    pub fn to_owned(&self) -> ParsedSection<'static> {        ParsedSection {            section_header: self.section_header.to_owned(),            events: self.events.iter().map(Event::to_owned).collect(),        }    }} impl Display for ParsedSection<'_> {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "{}", self.section_header)?;        for event in &self.events {            event.fmt(f)?;        }        Ok(())    }} macro_rules! generate_case_insensitive {    ($name:ident, $cow_inner_type:ty, $comment:literal) => {        #[doc = $comment]        #[derive(Clone, Eq, Ord, Debug, Default)]        pub struct $name<'a>(pub Cow<'a, $cow_inner_type>);         impl $name<'_> {            /// Coerces into an owned instance. This differs from the standard            /// [`clone`] implementation as calling clone will _not_ copy the            /// borrowed variant, while this method will. In other words:            ///            /// | Borrow type | `.clone()` | `to_owned()` |            /// | ----------- | ---------- | ------------ |            /// | Borrowed    | Borrowed   | Owned        |            /// | Owned       | Owned      | Owned        |            ///            /// This can be most effectively seen by the differing lifetimes            /// between the two. This method guarantees a `'static` lifetime,            /// while `clone` does not.            ///            /// [`clone`]: Self::clone            #[must_use]            pub fn to_owned(&self) -> $name<'static> {                $name(Cow::Owned(self.0.clone().into_owned()))            }        }         impl PartialEq for $name<'_> {            fn eq(&self, other: &Self) -> bool {                self.0.eq_ignore_ascii_case(&other.0)            }        }         impl Display for $name<'_> {            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {                self.0.fmt(f)            }        }         impl PartialOrd for $name<'_> {            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {                self.0                    .to_ascii_lowercase()                    .partial_cmp(&other.0.to_ascii_lowercase())            }        }         impl std::hash::Hash for $name<'_> {            fn hash<H: std::hash::Hasher>(&self, state: &mut H) {                self.0.to_ascii_lowercase().hash(state)            }        }         impl<'a> From<&'a str> for $name<'a> {            fn from(s: &'a str) -> Self {                Self(Cow::Borrowed(s))            }        }         impl<'a> From<Cow<'a, str>> for $name<'a> {            fn from(s: Cow<'a, str>) -> Self {                Self(s)            }        }         impl<'a> std::ops::Deref for $name<'a> {            type Target = $cow_inner_type;             fn deref(&self) -> &Self::Target {                &self.0            }        }    };} generate_case_insensitive!(    SectionHeaderName,    str,    "Wrapper struct for section header names, since section headers are case-insensitive."); generate_case_insensitive!(    Key,    str,    "Wrapper struct for key names, since keys are case-insensitive."); /// A parsed section header, containing a name and optionally a subsection name.////// Note that section headers must be parsed as valid ASCII, and thus all valid/// instances must also necessarily be valid UTF-8, which is why we use a/// [`str`] instead of [`[u8]`].#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedSectionHeader<'a> {    /// The name of the header.    pub name: SectionHeaderName<'a>,    /// The separator used to determine if the section contains a subsection.    /// This is either a period `.` or a string of whitespace. Note that    /// reconstruction of subsection format is dependent on this value. If this    /// is all whitespace, then the subsection name needs to be surrounded by    /// quotes to have perfect reconstruction.    pub separator: Option<Cow<'a, str>>,    /// The subsection name without quotes if any exist.    pub subsection_name: Option<Cow<'a, str>>,} impl ParsedSectionHeader<'_> {    /// Generates a byte representation of the value. This should be used when    /// non-UTF-8 sequences are present or a UTF-8 representation can't be    /// guaranteed.    #[must_use]    pub fn to_vec(&self) -> Vec<u8> {        self.into()    }     /// Coerces into an owned instance. This differs from the standard [`clone`]    /// implementation as calling clone will _not_ copy the borrowed variant,    /// while this method will. In other words:    ///    /// | Borrow type | `.clone()` | `to_owned()` |    /// | ----------- | ---------- | ------------ |    /// | Borrowed    | Borrowed   | Owned        |    /// | Owned       | Owned      | Owned        |    ///    /// This can be most effectively seen by the differing lifetimes between the    /// two. This method guarantees a `'static` lifetime, while `clone` does    /// not.    ///    /// [`clone`]: Self::clone    #[must_use]    pub fn to_owned(&self) -> ParsedSectionHeader<'static> {        ParsedSectionHeader {            name: self.name.to_owned(),            separator: self.separator.clone().map(|v| Cow::Owned(v.into_owned())),            subsection_name: self.subsection_name.clone().map(|v| Cow::Owned(v.into_owned())),        }    }} impl Display for ParsedSectionHeader<'_> {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "[{}", self.name)?;         if let Some(v) = &self.separator {            // Separator must be utf-8            v.fmt(f)?;            let subsection_name = self.subsection_name.as_ref().unwrap();            if v == "." {                subsection_name.fmt(f)?;            } else {                write!(f, "\"{}\"", subsection_name)?;            }        }         write!(f, "]")    }} impl From<ParsedSectionHeader<'_>> for Vec<u8> {    fn from(header: ParsedSectionHeader) -> Self {        header.into()    }} impl From<&ParsedSectionHeader<'_>> for Vec<u8> {    fn from(header: &ParsedSectionHeader) -> Self {        header.to_string().into_bytes()    }} impl<'a> From<ParsedSectionHeader<'a>> for Event<'a> {    fn from(header: ParsedSectionHeader) -> Event {        Event::SectionHeader(header)    }} /// A parsed comment event containing the comment marker and comment.#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]pub struct ParsedComment<'a> {    /// The comment marker used. This is either a semicolon or octothorpe.    pub comment_tag: char,    /// The parsed comment.    pub comment: Cow<'a, [u8]>,} impl ParsedComment<'_> {    /// Coerces into an owned instance. This differs from the standard [`clone`]    /// implementation as calling clone will _not_ copy the borrowed variant,    /// while this method will. In other words:    ///    /// | Borrow type | `.clone()` | `to_owned()` |    /// | ----------- | ---------- | ------------ |    /// | Borrowed    | Borrowed   | Owned        |    /// | Owned       | Owned      | Owned        |    ///    /// This can be most effectively seen by the differing lifetimes between the    /// two. This method guarantees a `'static` lifetime, while `clone` does    /// not.    ///    /// [`clone`]: Self::clone    #[must_use]    pub fn to_owned(&self) -> ParsedComment<'static> {        ParsedComment {            comment_tag: self.comment_tag,            comment: Cow::Owned(self.comment.to_vec()),        }    }} impl Display for ParsedComment<'_> {    /// Note that this is a best-effort attempt at printing an comment. If    /// there are non UTF-8 values in your config, this will _NOT_ render    /// as read.    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        self.comment_tag.fmt(f)?;        if let Ok(s) = std::str::from_utf8(&self.comment) {            s.fmt(f)        } else {            write!(f, "{:02x?}", self.comment)        }    }} impl From<ParsedComment<'_>> for Vec<u8> {    fn from(c: ParsedComment) -> Self {        c.into()    }} impl From<&ParsedComment<'_>> for Vec<u8> {    fn from(c: &ParsedComment) -> Self {        let mut values = vec![c.comment_tag as u8];        values.extend(c.comment.iter());        values    }} /// A parser error reports the one-indexed line number where the parsing error/// occurred, as well as the last parser node and the remaining data to be/// parsed.#[derive(PartialEq, Debug)]pub struct Error<'a> {    line_number: usize,    last_attempted_parser: ParserNode,    parsed_until: Cow<'a, [u8]>,} impl Error<'_> {    /// The one-indexed line number where the error occurred. This is determined    /// by the number of newlines that were successfully parsed.    #[must_use]    pub const fn line_number(&self) -> usize {        self.line_number + 1    }     /// The remaining data that was left unparsed.    #[must_use]    pub fn remaining_data(&self) -> &[u8] {        &self.parsed_until    }     /// Coerces into an owned instance. This differs from the standard [`clone`]    /// implementation as calling clone will _not_ copy the borrowed variant,    /// while this method will. In other words:    ///    /// | Borrow type | `.clone()` | `to_owned()` |    /// | ----------- | ---------- | ------------ |    /// | Borrowed    | Borrowed   | Owned        |    /// | Owned       | Owned      | Owned        |    ///    /// This can be most effectively seen by the differing lifetimes between the    /// two. This method guarantees a `'static` lifetime, while `clone` does    /// not.    ///    /// [`clone`]: std::clone::Clone::clone    #[must_use]    pub fn to_owned(&self) -> Error<'static> {        Error {            line_number: self.line_number,            last_attempted_parser: self.last_attempted_parser,            parsed_until: self.parsed_until.clone().into_owned().into(),        }    }} impl Display for Error<'_> {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        let data_size = self.parsed_until.len();        let data = std::str::from_utf8(&self.parsed_until);        write!(            f,            "Got an unexpected token on line {} while trying to parse a {}: ",            self.line_number + 1,            self.last_attempted_parser,        )?;         match (data, data_size) {            (Ok(data), _) if data_size > 10 => {                write!(f, "'{}' ... ({} characters omitted)", &data[..10], data_size - 10)            }            (Ok(data), _) => write!(f, "'{}'", data),            (Err(_), _) if data_size > 10 => write!(                f,                "'{:02x?}' ... ({} characters omitted)",                &self.parsed_until[..10],                data_size - 10            ),

Lines 1–500 of 1972.