Hello, can anyone help me write this function without using enumerate / join?
fn draw(list: &[(String, bool)], height: usize, y: usize, offset: usize) {
eprint!("\x1b[2J\x1b[H");
for (i, (name, is_dir)) in list.iter().skip(offset).take(height).enumerate() {
let newline = if i > 0 { "\n" } else { "" };
let slash = if *is_dir { "/" } else { "" };
eprint!("{newline}{slash}{name}");
}
eprint!("\x1b[{};1H", y - offset + 1);
}
That's the closest I got:
fn draw(list: &[(String, bool)], height: usize, y: usize, offset: usize) {
eprint!("\x1b[2J\x1b[H");
let mut first = true;
for (name, is_dir) in list.iter().skip(offset).take(height) {
let newline = if first { "" } else { "\n" };
let slash = if *is_dir { "/" } else { "" };
eprint!("{newline}{slash}{name}");
first = false;
}
eprint!("\x1b[{};1H", y - offset + 1);
}
But using this first variable seems wrong.
Full code available here
You could advance the iterator first by one position by calling next, and then consume the rest of the iterator.
Yes, but in this version, I don't like that slash is repeated twice.
...
let slash = if *is_dir { "/" } else { "" };
...
let slash = if *is_dir { "/" } else { "" };
Use map to remove some redundancy.
let mut iter =
list.iter()
.skip(offset)
.take(height)
.map(|(n, d)| if *d { (n, "/") } else { (n, "") });
eprint!("\x1b[2J\x1b[H");
if let Some((name, slash)) = iter.next() {
eprint!("{slash}{name}");
}
for (name, slash) in iter {
eprint!("\n{slash}{name}");
}
eprint!("\x1b[{};1H", y - offset + 1);
conqp
June 29, 2026, 9:54pm
5
use itertools::Itertools;
fn draw(list: &[(String, bool)], height: usize, y: usize, offset: usize) {
eprint!("\x1b[2J\x1b[H");
for name in list
.iter()
.skip(offset)
.take(height)
.map(|(name, is_dir)| format!("{}{name}", if *is_dir { "/" } else { "" }))
.intersperse("\n".into())
{
eprint!("{name}");
}
eprint!("\x1b[{};1H", y - offset + 1);
}
keyko
June 29, 2026, 9:55pm
6
This is possibly wrong but I struggled to follow the intend so I created a few types (playground ):
struct File {
name: String,
is_dir: bool,
}
impl File {
fn new(name: &str, is_dir: bool) -> Self {
File {
name: String::from(name),
is_dir,
}
}
}
struct Window {
skip: usize,
take: usize,
}
/// Something with a window of files
fn draw(list: &[File], window: Window, y: usize) {
eprint!("\x1b[2J\x1b[H");
let mut file_iter = list.iter().skip(window.skip).take(window.take);
let File { name, is_dir } = file_iter.next().unwrap();
let slash = if *is_dir { "/" } else { "" };
eprint!("{slash}{}", name);
for File { name, is_dir } in file_iter {
let slash = if *is_dir { "/" } else { "" };
eprint!("\n{slash}{}", name);
}
eprint!("\x1b[{};1H", y - window.skip + 1);
}
fn main() {
let list = [
File::new("hello", true),
File::new("hello", false),
File::new("hellw", true),
];
let window = Window { skip: 1, take: 1 };
draw(&list, window, 1);
}
Thanks for the answers, in the end I came to this version:
fn list(path: &Path) -> Vec<(String, bool)> {
let mut entries = Vec::new();
for entry in read_dir(path).into_iter().flatten().flatten() {
let is_dir = entry.file_type().is_ok_and(|file_type| file_type.is_dir());
let mut name = entry.file_name().to_string_lossy().into_owned();
if is_dir {
name.insert(0, '/');
}
entries.push((name, is_dir));
}
entries.sort_unstable_by(|a, b| (!a.1, &a.0).cmp(&(!b.1, &b.0)));
entries.iter_mut().skip(1).for_each(|(name, _)| name.insert(0, '\n'));
entries
}
fn draw(list: &[(String, bool)], height: usize, y: usize, offset: usize) {
eprint!("\x1b[2J\x1b[H");
for (name, _) in list.iter().skip(offset).take(height) {
eprint!("{name}");
}
eprint!("\x1b[{};1H", y - offset + 1);
}