vfs: add is_terminal()
This commit is contained in:
parent
8dbbc07ff6
commit
4acb148d0e
@ -93,12 +93,6 @@ impl CharFile {
|
||||
self.device.0.read_nonblocking(buf)
|
||||
}
|
||||
}
|
||||
// if self.read {
|
||||
// self.device.0.read(buf)
|
||||
// } else {
|
||||
// Err(Error::InvalidOperation)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
if !self.write {
|
||||
@ -111,10 +105,8 @@ impl CharFile {
|
||||
self.device.0.write_nonblocking(buf)
|
||||
}
|
||||
}
|
||||
// if self.write {
|
||||
// self.device.0.write(buf)
|
||||
// } else {
|
||||
// Err(Error::ReadOnly)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
self.device.0.is_terminal()
|
||||
}
|
||||
}
|
||||
|
@ -341,6 +341,14 @@ impl File {
|
||||
|
||||
/// Performs a device-specific request
|
||||
pub fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> {
|
||||
match req {
|
||||
DeviceRequest::IsTerminal(value) => {
|
||||
*value = self.is_terminal();
|
||||
return Ok(());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match self {
|
||||
Self::Char(f) => f.device.device_request(req),
|
||||
Self::Block(f) => f.device.device_request(req),
|
||||
@ -375,6 +383,14 @@ impl File {
|
||||
_ => Err(Error::InvalidOperation),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_terminal(&self) -> bool {
|
||||
match self {
|
||||
Self::Char(dev) => dev.is_terminal(),
|
||||
Self::PtySlave(_) | Self::PtyMaster(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageProvider for File {
|
||||
|
@ -29,6 +29,8 @@ pub enum DeviceRequest {
|
||||
GetTerminalSize(MaybeUninit<terminal::TerminalSize>),
|
||||
/// Sets a foreground process group ID for the terminal
|
||||
SetTerminalGroup(ProcessGroupId),
|
||||
/// Returns `true` if a file/device is a terminal
|
||||
IsTerminal(bool),
|
||||
|
||||
/// "Acquires" ownership of the device, preventing others from accessing it
|
||||
AcquireDevice,
|
||||
|
@ -28,7 +28,7 @@ pub use abi::io::{
|
||||
FileType, OpenOptions, PipeOptions, RawFd, SeekFrom, TimerOptions,
|
||||
};
|
||||
|
||||
use abi::{error::Error, process::ProcessOption, util::FixedString};
|
||||
use abi::{error::Error, io::DeviceRequest, process::ProcessOption, util::FixedString};
|
||||
use alloc::string::String;
|
||||
|
||||
pub fn current_directory<T, F: FnOnce(&str) -> T>(mapper: F) -> Result<T, Error> {
|
||||
@ -50,3 +50,12 @@ pub fn set_current_directory(path: &str) -> Result<(), Error> {
|
||||
unsafe { crate::sys::set_process_option(&mut option) }?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_terminal(f: RawFd) -> bool {
|
||||
let mut option = DeviceRequest::IsTerminal(false);
|
||||
let res = unsafe { crate::sys::device_request(f, &mut option) };
|
||||
match (res, option) {
|
||||
(Ok(()), DeviceRequest::IsTerminal(true)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
use std::{
|
||||
fmt,
|
||||
io::{self, Read, Stdin},
|
||||
io::{self, Read},
|
||||
};
|
||||
|
||||
use crate::TermInput;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TermKey {
|
||||
Char(char),
|
||||
@ -23,7 +25,7 @@ pub trait ReadChar {
|
||||
fn read_char(&mut self) -> Result<char, InputError>;
|
||||
}
|
||||
|
||||
impl ReadChar for Stdin {
|
||||
impl ReadChar for TermInput {
|
||||
fn read_char(&mut self) -> Result<char, InputError> {
|
||||
let mut buf = [0; 4];
|
||||
self.read_exact(&mut buf[..1])
|
||||
|
@ -1,9 +1,7 @@
|
||||
#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))]
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
io::{self, stdin, stdout, Stdin, Stdout, Write},
|
||||
os::fd::{AsRawFd, RawFd},
|
||||
fmt, fs::File, io::{self, stdin, stdout, IsTerminal, Read, Stdin, Stdout, Write}, os::fd::{AsRawFd, RawFd}
|
||||
};
|
||||
|
||||
pub use self::{input::ReadChar, sys::RawMode};
|
||||
@ -43,8 +41,31 @@ pub trait RawTerminal {
|
||||
fn raw_size(&self) -> io::Result<(usize, usize)>;
|
||||
}
|
||||
|
||||
enum TermInput {
|
||||
Stdin(Stdin),
|
||||
File(File)
|
||||
}
|
||||
|
||||
impl Read for TermInput {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
Self::Stdin(stdin) => stdin.read(buf),
|
||||
Self::File(file) => file.read(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TermInput {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
match self {
|
||||
Self::Stdin(stdin) => stdin.as_raw_fd(),
|
||||
Self::File(file) => file.as_raw_fd(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Term {
|
||||
stdin: Stdin,
|
||||
stdin: TermInput,
|
||||
stdout: Stdout,
|
||||
raw: RawMode,
|
||||
}
|
||||
@ -134,9 +155,8 @@ impl RawTerminal for Stdout {
|
||||
}
|
||||
|
||||
impl Term {
|
||||
pub fn is_tty() -> bool {
|
||||
// TODO
|
||||
true
|
||||
pub fn stdin_is_tty() -> bool {
|
||||
stdin().is_terminal()
|
||||
}
|
||||
|
||||
pub fn input_fd(&self) -> RawFd {
|
||||
@ -145,6 +165,12 @@ impl Term {
|
||||
|
||||
pub fn open() -> Result<Self, Error> {
|
||||
let stdin = stdin();
|
||||
let stdin = if stdin.is_terminal() {
|
||||
TermInput::Stdin(stdin)
|
||||
} else {
|
||||
let file = File::open("/dev/tty")?;
|
||||
TermInput::File(file)
|
||||
};
|
||||
let mut stdout = stdout();
|
||||
|
||||
// Set stdin to raw mode
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::{
|
||||
io::{self, Stdin, Stdout},
|
||||
io::{self, Stdout},
|
||||
mem::MaybeUninit,
|
||||
os::yggdrasil::io::{
|
||||
os::{fd::AsRawFd, yggdrasil::io::{
|
||||
device::{DeviceRequest, FdDeviceRequest},
|
||||
terminal::{update_terminal_options, TerminalOptions},
|
||||
},
|
||||
}},
|
||||
};
|
||||
|
||||
pub struct RawMode(TerminalOptions);
|
||||
@ -13,15 +13,15 @@ impl RawMode {
|
||||
/// # Safety
|
||||
///
|
||||
/// May leave the terminal in broken state, unsafe.
|
||||
pub unsafe fn enter(stdin: &Stdin) -> io::Result<Self> {
|
||||
update_terminal_options(stdin, |_| TerminalOptions::raw_input()).map(RawMode)
|
||||
pub unsafe fn enter<F: AsRawFd>(stdin: &F) -> io::Result<Self> {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| TerminalOptions::raw_input()).map(RawMode)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// May leave the terminal in broken state, unsafe.
|
||||
pub unsafe fn leave(&self, stdin: &Stdin) {
|
||||
update_terminal_options(stdin, |_| self.0).ok();
|
||||
pub unsafe fn leave<F: AsRawFd>(&self, stdin: &F) {
|
||||
update_terminal_options(stdin.as_raw_fd(), |_| self.0).ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !Term::is_tty() {
|
||||
if !Term::stdin_is_tty() {
|
||||
eprintln!("Not a tty");
|
||||
return;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
fmt::{self, Write},
|
||||
io,
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
@ -160,9 +161,15 @@ struct Args {
|
||||
filename: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
fn main() -> ExitCode {
|
||||
// TODO check if running in a terminal
|
||||
let args = Args::parse();
|
||||
let view = View::open(&args.filename, !args.no_bar).unwrap();
|
||||
view.run()
|
||||
match view.run() {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(error) => {
|
||||
yggdrasil_rt::debug_trace!("view: {error}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user