New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Deno.lines #2101
Add Deno.lines #2101
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ export { | |
export { | ||
copy, | ||
toAsyncIterator, | ||
lines, | ||
ReadResult, | ||
SeekMode, | ||
Reader, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
// Documentation liberally lifted from them too. | ||
// Thank you! We love Go! | ||
|
||
import { TextDecoder } from "./text_encoding"; | ||
|
||
// The bytes read during an I/O call and a boolean indicating EOF. | ||
export interface ReadResult { | ||
nread: number; | ||
|
@@ -159,3 +161,31 @@ export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> { | |
} | ||
}; | ||
} | ||
|
||
/** Read lines asynchronously from `r`. | ||
* | ||
* for await (const line of Deno.lines(reader)) { | ||
* console.log(line); | ||
* } | ||
*/ | ||
export async function* lines(r: Reader): AsyncIterableIterator<string> { | ||
const decoder = new TextDecoder(); | ||
let scratch = ""; | ||
|
||
for await (const chunk of toAsyncIterator(r)) { | ||
scratch += decoder.decode(chunk); | ||
|
||
let newLineIndex = scratch.indexOf("\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't forget about windows carriage return line feeds There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using something like this for the remaining lines too. let crLf = false;
let idx = newLineIndex;
if(scratch[idx-1]=="\r") {
idx--;
crlf = true;
}
const line = scratch.slice(0, idx);
...
const remainingLines;
if(crLF) {
remainingLines = scratch.split("\n");
} else {
remainingLines = scratch.split("\r\n");
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @johnsonjo4531 you're right, that's where your implementation is better :) let's wait on |
||
|
||
if (newLineIndex > -1) { | ||
const line = scratch.slice(0, newLineIndex); | ||
scratch = scratch.slice(newLineIndex + 1); | ||
yield line; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't only one yield per chunk mean scratch could grow linearly? |
||
} | ||
} | ||
|
||
const remainingLines = scratch.split("\n"); | ||
for (const line of remainingLines) { | ||
yield line; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we could import code from deno_std here. The correct way to solve this is to use BufReader in std/io/bufio.ts
https://github.com/denoland/deno_std/blob/master/io/bufio.ts#L220
In order to use that code, we need to change //js/ to use extensions in the imports... (cc @kitsonk )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that is complicated (using extensions). I was planning to tackle it in the medium term. Essentially we have to replace rollup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should move bufio into //js then (problem is that it will likely bring all of std/io with it as dependencies)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe "lines" should just be in deno_std instead of core..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like
BufReader
provides a nice way to solvelines
👍Reading line by line is such a common operation that IMHO it should be
Deno.lines
instead of living in deno_std.It's greatly illustrated by @ry's example. This is super simple:
This is not:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bartlomieju I agree it would be great to have built in to the CLI... but I really want to ensure that we use the proper bufio infrastructure to solve these problems rather than having a bunch of one-off algorithms for buffering. So either we need to first be able to import deno_std code into the CLI (ideal) or move bufio from deno_std into the main repo (less ideal)
Closing this one for now. Thanks @bartlomieju !