Skip to content

Commit aacc5b1

Browse files
authored
[NFCI] Use line_ending_or_eof consistently in parsers (#300)
This is useful for line-oriented parsers that may consume input with no trailing newline character. While this is a [violation of the POSIX spec][posix], VS Code [does it by default][vscode]. [posix]: https://stackoverflow.com/a/729795 [vscode]: https://stackoverflow.com/questions/44704968/visual-studio-code-insert-newline-at-the-end-of-files Split off from #297
1 parent 910c4c3 commit aacc5b1

File tree

4 files changed

+25
-7
lines changed

4 files changed

+25
-7
lines changed

src/ghci/parse/eval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use miette::miette;
77
use winnow::ascii::line_ending;
88
use winnow::ascii::space0;
99
use winnow::combinator::alt;
10-
use winnow::combinator::eof;
1110
use winnow::combinator::opt;
1211
use winnow::combinator::peek;
1312
use winnow::combinator::repeat;
@@ -16,6 +15,7 @@ use winnow::Located;
1615
use winnow::PResult;
1716
use winnow::Parser;
1817

18+
use crate::ghci::parse::lines::line_ending_or_eof;
1919
use crate::ghci::GhciCommand;
2020

2121
use super::lines::rest_of_line;
@@ -173,7 +173,7 @@ fn multiline_eval_command(input: &mut Located<&str>) -> PResult<ByteSpanCommand>
173173
.with_span()
174174
.parse_next(input)?;
175175
multiline_eval_end.parse_next(input)?;
176-
let _ = (space0, alt((line_ending, eof))).parse_next(input)?;
176+
let _ = (space0, line_ending_or_eof).parse_next(input)?;
177177

178178
Ok(ByteSpanCommand {
179179
// `command` ends with a newline so we put a newline after the `:{` but not before the

src/ghci/parse/ghc_message/compilation_summary.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use winnow::ascii::digit1;
2-
use winnow::ascii::line_ending;
32
use winnow::combinator::alt;
43
use winnow::combinator::opt;
54
use winnow::PResult;
65
use winnow::Parser;
76

7+
use crate::ghci::parse::lines::line_ending_or_eof;
88
use crate::ghci::parse::CompilationResult;
99

1010
use super::GhcMessage;
@@ -54,7 +54,7 @@ pub fn compilation_summary(input: &mut &str) -> PResult<GhcMessage> {
5454
let _ = " module".parse_next(input)?;
5555
let _ = opt("s").parse_next(input)?;
5656
let _ = " loaded.".parse_next(input)?;
57-
let _ = line_ending.parse_next(input)?;
57+
let _ = line_ending_or_eof.parse_next(input)?;
5858

5959
Ok(GhcMessage::Summary(CompilationSummary {
6060
result,

src/ghci/parse/ghc_message/module_import_cycle_diagnostic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use camino::Utf8PathBuf;
22
use itertools::Itertools;
3-
use winnow::ascii::line_ending;
43
use winnow::ascii::space1;
54
use winnow::combinator::alt;
65
use winnow::combinator::opt;
@@ -10,6 +9,7 @@ use winnow::PResult;
109
use winnow::Parser;
1110

1211
use crate::ghci::parse::haskell_grammar::module_name;
12+
use crate::ghci::parse::lines::line_ending_or_eof;
1313
use crate::ghci::parse::lines::rest_of_line;
1414
use crate::ghci::parse::Severity;
1515

@@ -57,7 +57,7 @@ pub fn module_import_cycle_diagnostic(input: &mut &str) -> PResult<Vec<GhcMessag
5757
"Module graph contains a cycle:",
5858
))
5959
.parse_next(input)?;
60-
let _ = line_ending.parse_next(input)?;
60+
let _ = line_ending_or_eof.parse_next(input)?;
6161
repeat(1.., parse_import_cycle_line).parse_next(input)
6262
}
6363

src/ghci/parse/lines.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ where
3434
<I as Stream>::Slice: SliceLen,
3535
{
3636
let line = till_line_ending.parse_next(input)?;
37-
let ending = alt((line_ending, eof)).parse_next(input)?;
37+
let ending = line_ending_or_eof.parse_next(input)?;
3838

3939
if line.slice_len() == 0 && ending.slice_len() == 0 {
4040
Err(ErrMode::Backtrack(ContextError::new()))
@@ -43,6 +43,24 @@ where
4343
}
4444
}
4545

46+
/// Parse a line ending or the end of the file.
47+
///
48+
/// This is useful for line-oriented parsers that may consume input with no trailing newline
49+
/// character. While this is a [violation of the POSIX spec][posix], VS Code [does it by
50+
/// default][vscode].
51+
///
52+
/// [posix]: https://stackoverflow.com/a/729795
53+
/// [vscode]: https://stackoverflow.com/questions/44704968/visual-studio-code-insert-newline-at-the-end-of-files
54+
pub fn line_ending_or_eof<I>(input: &mut I) -> PResult<<I as Stream>::Slice>
55+
where
56+
I: Stream + StreamIsPartial + for<'i> FindSlice<&'i str> + for<'i> Compare<&'i str>,
57+
<I as Stream>::Token: AsChar,
58+
<I as Stream>::Token: Clone,
59+
<I as Stream>::Slice: SliceLen,
60+
{
61+
alt((line_ending, eof)).parse_next(input)
62+
}
63+
4664
#[cfg(test)]
4765
mod tests {
4866
use pretty_assertions::assert_eq;

0 commit comments

Comments
 (0)