mvp
This commit is contained in:
parent
0a2ec5f358
commit
883b94f1eb
5 changed files with 203 additions and 55 deletions
|
@ -5,3 +5,4 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
nix = { version = "0.30.1", features = ["term", "process", "fs"], default-features = false }
|
||||
iced = "0.13.1"
|
||||
|
|
6
flake.lock
generated
6
flake.lock
generated
|
@ -22,11 +22,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1751011381,
|
||||
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
|
||||
"lastModified": 1751271578,
|
||||
"narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
|
||||
"rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
18
package.nix
18
package.nix
|
@ -1,9 +1,16 @@
|
|||
{
|
||||
busybox-sandbox-shell,
|
||||
expat,
|
||||
fontconfig,
|
||||
freetype,
|
||||
lib,
|
||||
libGL,
|
||||
libxkbcommon,
|
||||
makeWrapper,
|
||||
naersk,
|
||||
pkg-config,
|
||||
wayland,
|
||||
xorg,
|
||||
...
|
||||
}:
|
||||
naersk.buildPackage rec {
|
||||
|
@ -11,6 +18,17 @@ naersk.buildPackage rec {
|
|||
src = ./.;
|
||||
buildInputs = [
|
||||
busybox-sandbox-shell
|
||||
expat
|
||||
fontconfig
|
||||
freetype
|
||||
freetype.dev
|
||||
libGL
|
||||
libxkbcommon
|
||||
wayland
|
||||
xorg.libX11
|
||||
xorg.libXcursor
|
||||
xorg.libXi
|
||||
xorg.libXrandr
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
|
|
146
src/lib.rs
Normal file
146
src/lib.rs
Normal file
|
@ -0,0 +1,146 @@
|
|||
use iced::Element;
|
||||
use iced::widget::{column, scrollable, text, text_input};
|
||||
|
||||
use nix::pty::{ForkptyResult, forkpty};
|
||||
use nix::unistd::write;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::{AsFd, OwnedFd};
|
||||
use std::process::Command;
|
||||
|
||||
pub fn spawn_pty_with_shell(default_shell: String) -> OwnedFd {
|
||||
match unsafe { forkpty(None, None) } {
|
||||
Ok(fork_pty_res) => match fork_pty_res {
|
||||
ForkptyResult::Parent { master, .. } => {
|
||||
set_nonblock(&master);
|
||||
master
|
||||
}
|
||||
ForkptyResult::Child => {
|
||||
Command::new(&default_shell).spawn().unwrap();
|
||||
std::thread::sleep(std::time::Duration::MAX);
|
||||
std::process::exit(0);
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("failed to fork {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_fd(fd: &OwnedFd) -> Option<Vec<u8>> {
|
||||
let mut read_buffer = [0; 65536];
|
||||
let mut file = File::from(fd.try_clone().unwrap());
|
||||
file.flush();
|
||||
let file = file.read(&mut read_buffer);
|
||||
match file {
|
||||
Ok(file) => Some(read_buffer[..file].to_vec()),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_nonblock(fd: &OwnedFd) {
|
||||
let flags = nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_GETFL).unwrap();
|
||||
let mut flags =
|
||||
nix::fcntl::OFlag::from_bits(flags & nix::fcntl::OFlag::O_ACCMODE.bits()).unwrap();
|
||||
flags.set(nix::fcntl::OFlag::O_NONBLOCK, true);
|
||||
nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFL(flags)).unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Msg {
|
||||
HasInput,
|
||||
InputChanged(String),
|
||||
}
|
||||
|
||||
pub struct Model {
|
||||
screen_buffer: [u8; 65536],
|
||||
screen_buffer_index: usize,
|
||||
fd: OwnedFd,
|
||||
stdin: OwnedFd,
|
||||
input: String,
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn new(
|
||||
screen_buffer: [u8; 65536],
|
||||
screen_buffer_index: usize,
|
||||
fd: OwnedFd,
|
||||
stdin: OwnedFd,
|
||||
input: String,
|
||||
) -> Self {
|
||||
Model {
|
||||
screen_buffer,
|
||||
screen_buffer_index,
|
||||
fd,
|
||||
stdin,
|
||||
input,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, msg: Msg) {
|
||||
match msg {
|
||||
Msg::HasInput => {
|
||||
let mut write_buffer = self.input.as_bytes().to_vec();
|
||||
write_buffer.push(b'\n');
|
||||
write(self.fd.as_fd(), &mut write_buffer);
|
||||
self.input = String::new();
|
||||
let mut nored = 0;
|
||||
while nored <= 2 {
|
||||
let red = read_from_fd(&self.fd);
|
||||
match &red {
|
||||
Some(red) => {
|
||||
nored += 1;
|
||||
self.update_screen_buffer(red);
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
Msg::InputChanged(input) => self.input = input,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view(&self) -> Element<'_, Msg> {
|
||||
scrollable(column![
|
||||
text(String::from(
|
||||
String::from_utf8(self.screen_buffer.to_vec())
|
||||
.unwrap()
|
||||
.trim_end_matches('\0')
|
||||
)),
|
||||
text_input("", &self.input)
|
||||
.on_input(Msg::InputChanged)
|
||||
.on_submit(Msg::HasInput)
|
||||
])
|
||||
.into()
|
||||
}
|
||||
|
||||
fn update_screen_buffer(&mut self, vec: &Vec<u8>) {
|
||||
let offset = self.screen_buffer.iter().position(|&c| c == b'\0').unwrap();
|
||||
for (i, chr) in vec.iter().enumerate() {
|
||||
self.screen_buffer[i + offset] = chr.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Model {
|
||||
fn default() -> Self {
|
||||
let mut me = Self::new(
|
||||
[0; 65536],
|
||||
0,
|
||||
spawn_pty_with_shell("/home/mtgmonkey/.nix-profile/bin/dash".to_string()),
|
||||
std::io::stdin().as_fd().try_clone_to_owned().unwrap(),
|
||||
String::new(),
|
||||
);
|
||||
let mut nored = true;
|
||||
while nored {
|
||||
let red = read_from_fd(&me.fd);
|
||||
match red {
|
||||
Some(red) => {
|
||||
nored = false;
|
||||
me.update_screen_buffer(&red);
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
me
|
||||
}
|
||||
}
|
87
src/main.rs
87
src/main.rs
|
@ -1,56 +1,39 @@
|
|||
use nix::pty::{ForkptyResult, forkpty};
|
||||
use nix::unistd::{read, write};
|
||||
use iced::Element;
|
||||
use iced::widget::{button, text};
|
||||
|
||||
use nix::unistd::write;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
|
||||
use std::process::Command;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::{AsFd, OwnedFd};
|
||||
|
||||
fn main() {
|
||||
let default_shell = "/home/mtgmonkey/.nix-profile/bin/dash".to_string();
|
||||
let fd = spawn_pty_with_shell(default_shell);
|
||||
set_nonblock(&fd);
|
||||
let mut write_buffer = "tty\n".as_bytes().to_vec();
|
||||
write(fd.as_fd(), &mut write_buffer);
|
||||
loop {
|
||||
let red = read_from_fd(fd.try_clone().unwrap());
|
||||
match red {
|
||||
Some(red) => print!("{}", String::from_utf8(red).unwrap()),
|
||||
None => {
|
||||
let mut write_buffer = vec![];
|
||||
std::io::stdin().read_to_end(&mut write_buffer);
|
||||
write(fd.as_fd(), &mut write_buffer);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
use rust_term::*;
|
||||
|
||||
fn spawn_pty_with_shell(default_shell: String) -> OwnedFd {
|
||||
match (unsafe { forkpty(None, None) }) {
|
||||
Ok(fork_pty_res) => match fork_pty_res {
|
||||
ForkptyResult::Parent { master, .. } => master,
|
||||
ForkptyResult::Child => {
|
||||
Command::new(&default_shell).spawn().unwrap();
|
||||
std::thread::sleep(std::time::Duration::MAX);
|
||||
std::process::exit(0);
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("failed to fork {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_from_fd(fd: OwnedFd) -> Option<Vec<u8>> {
|
||||
let mut read_buffer = [0; 65536];
|
||||
let mut file = File::from(fd).read(&mut read_buffer);
|
||||
match file {
|
||||
Ok(file) => Some(read_buffer[..file].to_vec()),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_nonblock(fd: &OwnedFd) {
|
||||
let flags = nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_GETFL).unwrap();
|
||||
let mut flags =
|
||||
nix::fcntl::OFlag::from_bits(flags & nix::fcntl::OFlag::O_ACCMODE.bits()).unwrap();
|
||||
flags.set(nix::fcntl::OFlag::O_NONBLOCK, true);
|
||||
nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFL(flags)).unwrap();
|
||||
fn main() -> iced::Result {
|
||||
iced::run("test", Model::update, Model::view)
|
||||
/* let default_shell = "/home/mtgmonkey/.nix-profile/bin/dash".to_string();
|
||||
let fd = spawn_pty_with_shell(default_shell);
|
||||
let mut write_buffer = "tty\n".as_bytes().to_vec();
|
||||
write(fd.as_fd(), &mut write_buffer);
|
||||
loop {
|
||||
let red = read_from_fd(&fd);
|
||||
match red {
|
||||
Some(red) => print!("{}", String::from_utf8(red).unwrap()),
|
||||
None => {
|
||||
let mut read_buffer = [0; 65536];
|
||||
let mut file = File::from(std::io::stdin().as_fd().try_clone_to_owned().unwrap());
|
||||
file.flush();
|
||||
let file = file.read(&mut read_buffer);
|
||||
println!(
|
||||
"{}",
|
||||
match file {
|
||||
Ok(file) => write(fd.as_fd(), &read_buffer[..file]).unwrap(),
|
||||
Err(_) => 0,
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue