-
Notifications
You must be signed in to change notification settings - Fork 24
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 support for reading files to file-explorer #47
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 |
---|---|---|
|
@@ -7,6 +7,7 @@ use ctru::services::hid::KeyPad; | |
use ctru::services::{Apt, Hid}; | ||
use ctru::Gfx; | ||
use std::fs::DirEntry; | ||
use std::os::horizon::fs::MetadataExt; | ||
use std::path::{Path, PathBuf}; | ||
|
||
fn main() { | ||
|
@@ -74,8 +75,37 @@ impl<'a> FileExplorer<'a> { | |
} | ||
|
||
fn print_menu(&mut self) { | ||
println!("Viewing {}", self.path.display()); | ||
match std::fs::metadata(&self.path) { | ||
Ok(metadata) => { | ||
println!( | ||
"Viewing {} (size {} bytes, mode {:#o})", | ||
self.path.display(), | ||
metadata.len(), | ||
metadata.st_mode(), | ||
); | ||
|
||
if metadata.is_file() { | ||
self.print_file_contents(); | ||
// let the user continue navigating from the parent dir | ||
// after dumping the file | ||
self.path.pop(); | ||
self.print_menu(); | ||
return; | ||
} else if metadata.is_dir() { | ||
self.print_dir_entries(); | ||
} else { | ||
println!("unsupported file type: {:?}", metadata.file_type()); | ||
} | ||
} | ||
Err(e) => { | ||
println!("Failed to read {}: {}", self.path.display(), e) | ||
} | ||
}; | ||
|
||
println!("Start to exit, A to select an entry by number, B to go up a directory, X to set the path."); | ||
} | ||
|
||
fn print_dir_entries(&mut self) { | ||
let dir_listing = std::fs::read_dir(&self.path).expect("Failed to open path"); | ||
self.entries = Vec::new(); | ||
|
||
|
@@ -85,34 +115,49 @@ impl<'a> FileExplorer<'a> { | |
println!("{:2} - {}", i, entry.file_name().to_string_lossy()); | ||
self.entries.push(entry); | ||
|
||
// Paginate the output | ||
if (i + 1) % 20 == 0 { | ||
println!("Press A to go to next page, or Start to exit"); | ||
|
||
while self.apt.main_loop() { | ||
self.hid.scan_input(); | ||
let input = self.hid.keys_down(); | ||
|
||
if input.contains(KeyPad::KEY_A) { | ||
break; | ||
} | ||
|
||
if input.contains(KeyPad::KEY_START) { | ||
self.running = false; | ||
return; | ||
} | ||
|
||
self.gfx.wait_for_vblank(); | ||
} | ||
self.wait_for_page_down(); | ||
} | ||
} | ||
Err(e) => { | ||
println!("{} - Error: {}", i, e); | ||
} | ||
} | ||
} | ||
} | ||
|
||
println!("Start to exit, A to select an entry by number, B to go up a directory, X to set the path."); | ||
fn print_file_contents(&mut self) { | ||
match std::fs::read_to_string(&self.path) { | ||
Ok(contents) => { | ||
println!("File contents:\n{0:->80}", ""); | ||
println!("{contents}"); | ||
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. Interestingly, for a really long file this takes a noticeably long amount of time (30 seconds on my 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. How big is that file, out of curiosity? I only tested with this small one but anything on the order of 30s seems worth investigating. In particular I would not expect romfs to be slow, but I haven't looked too close at the io implementations for it... 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. It's 104 KB. I think it's just the default config, but here is the exact file (compressed so GitHub accepts it): 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. Yep, it looks like that they really needed a scroll effect, but since the console cooperative thread doesn’t yield the scroll blocks the whole app, and takes quite a while, too. 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. Oh, the scroll effect is semi-intentional? I guess fixing that would require libctru changes... 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. Maybe we should paginate the output here too? I wonder if we should move the pagination message to the lower screen to avoid interrupting the top screen's output. 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. Oops, good point, I think when I had BufReader here it made more sense but using 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. I think the prompt move should be as making a new temporary console and selecting it. |
||
println!("{0:->80}", ""); | ||
} | ||
Err(err) => { | ||
println!("Error reading file: {}", err); | ||
} | ||
} | ||
} | ||
|
||
/// Paginate output | ||
fn wait_for_page_down(&mut self) { | ||
println!("Press A to go to next page, or Start to exit"); | ||
|
||
while self.apt.main_loop() { | ||
self.hid.scan_input(); | ||
let input = self.hid.keys_down(); | ||
|
||
if input.contains(KeyPad::KEY_A) { | ||
break; | ||
} | ||
|
||
if input.contains(KeyPad::KEY_START) { | ||
self.running = false; | ||
return; | ||
} | ||
|
||
self.gfx.wait_for_vblank(); | ||
} | ||
} | ||
|
||
fn get_input_and_run(&mut self, action: impl FnOnce(&mut Self, String)) { | ||
|
@@ -154,11 +199,6 @@ impl<'a> FileExplorer<'a> { | |
} | ||
}; | ||
|
||
if !next_entry.file_type().unwrap().is_dir() { | ||
println!("Not a directory: {}", next_path_index); | ||
return; | ||
} | ||
|
||
self.console.clear(); | ||
self.path = next_entry.path(); | ||
self.print_menu(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
c��:7vi���z�`�n����ʢ��fb� |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
test | ||
test file contents | ||
|
||
another 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.
I see this error after reading
romfs:/test-file.txt
:This is probably due to the weird path handling? Maybe we should handle this case in the code until the underlying path issue is fixed?
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.
Yes, this is because of Meziu/rust-horizon#13 as far as I know. I didn't want it to block this PR because I think it was an issue before but got more exposed by this PR.
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, not blocking, but maybe we can do something like in
run
withself.path.components().count() > 1
to avoid popping the path in this case. Or maybe we just need to reset it manually. Up to you.