+
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions src/usr/draw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
use crate::api::console::Style;
use crate::api::fs;
use crate::api::process::ExitCode;
use crate::api::vga;
use crate::api::font::Font;
use crate::api::syscall;
use crate::api::clock;
use crate::sys::console;
use crate::usr::shell;

use alloc::string::ToString;
use alloc::format;
use alloc::vec::Vec;
use bit_field::BitField;
use core::convert::TryFrom;

const WIDTH: usize = 320;
const HEIGHT: usize = 200;

const BLACK: u8 = 0x00;
const GREEN: u8 = 0x3A;

const FONT: &str = "/ini/fonts/zap-light-8x16.psf";

#[derive(PartialEq)]
enum Mode {
Text,
Graphic,
}

struct Config {
mode: Mode
}

impl Config {
pub fn new() -> Self {
Self { mode: Mode::Text }
}

pub fn text_mode(&mut self) {
if self.mode == Mode::Graphic {
vga::text_mode();
self.mode = Mode::Text;
}
}

pub fn graphic_mode(&mut self) {
if self.mode == Mode::Text {
vga::graphic_mode();
self.mode = Mode::Graphic;
}
}
}

pub fn main(args: &[&str]) -> Result<(), ExitCode> {
if args.len() == 1 {
help();
return Err(ExitCode::UsageError);
}
if args.contains(&"-h") || args.contains(&"--help") {
help();
return Ok(());
}
let mut center = false;
let mut interval: Option<f64> = None;
let mut command = None;
let mut text = None;
let mut i = 1;
let n = args.len();
while i < n {
match args[i] {
"-h" | "--help" => {
help();
return Ok(());
}
"-c" | "--center" => {
center = true;
}
"-i" | "--interval" => {
if i + 1 < n {
i += 1;
interval = args[i].parse().ok();
} else {
error!("Missing interval");
return Err(ExitCode::UsageError);
}
}
"-e" | "--execute" => {
if i + 1 < n {
i += 1;
command = Some(args[i]);
} else {
error!("Missing command");
return Err(ExitCode::UsageError);
}
}
"-t" | "--text" => {
if i + 1 < n {
i += 1;
text = Some(args[i]);
} else {
error!("Missing text");
return Err(ExitCode::UsageError);
}
}
_ => {
error!("Invalid argument");
return Err(ExitCode::UsageError);
}
}
i += 1;
}
let mut config = Config::new();
if let Ok(buf) = fs::read_to_bytes(&FONT) {
if let Ok(fnt) = Font::try_from(&buf[..]) {
let w = 8;
let h = fnt.height as usize;
let max_cols = WIDTH / w;
let max_rows = HEIGHT / h;
let chars: Vec<_> = fnt.data.chunks(h).collect();

let mut draw = true;
let mut start = clock::epoch_time();
loop {
if console::end_of_text() {
break;
}
if let Some(i) = interval {
draw = draw || (clock::epoch_time() > start + i);
}
if draw {
start = clock::epoch_time();
let out = if let Some(cmd) = command {
let tmp = "/tmp/draw.tmp";
let cmd = format!("{} => {}", cmd, tmp);
if shell::exec(&cmd).is_err() {
config.text_mode();
return Err(ExitCode::Failure);
}
let res = fs::read_to_string(tmp).unwrap();
let _ = fs::delete(tmp);
res.trim().to_string()
} else {
text.unwrap().to_string()
};
let pad = " ".repeat(if center {
(max_cols.saturating_sub(out.len()) / 2)
+ (max_rows / 2) * max_cols
} else {
0
});
let out = format!("{}{}", pad, out);
let mut img = [BLACK; WIDTH * HEIGHT];
for (i, c) in out.chars().enumerate() {
if i > max_cols * max_rows {
break;
}
let col = i % max_cols;
let row = i / max_cols;
let offset = col * w + row * h * WIDTH;
for x in 0..w {
for y in 0..h {
if chars[c as usize][y].get_bit(w - 1 - x) {
img[x + y * WIDTH + offset] = GREEN;
}
}
}
}

config.graphic_mode();

let dev = "/dev/vga/buffer";
if !fs::is_device(dev) || fs::write(dev, &img).is_err() {
config.text_mode();
error!("Could not write to '{}'", dev);
return Err(ExitCode::Failure);
}
draw = false;
}
syscall::sleep(0.1);
}
}
}

config.text_mode();
Ok(())
}

fn help() {
let csi_option = Style::color("aqua");
let csi_title = Style::color("yellow");
let csi_reset = Style::reset();
println!(
"{}Usage:{} draw {}<options>{1}",
csi_title, csi_reset, csi_option
);
println!();
println!("{}Options:{}", csi_title, csi_reset);
println!(
" {0}-t{1}, {0}--text <text>{1} Draw <text>",
csi_option, csi_reset
);
println!(
" {0}-e{1}, {0}--execute <command>{1} Draw output of <command>",
csi_option, csi_reset
);
println!(
" {0}-i{1}, {0}--interval <seconds>{1} Run every <seconds>",
csi_option, csi_reset
);
println!(
" {0}-c{1}, {0}--center{1} Center text",
csi_option, csi_reset
);
}
1 change: 1 addition & 0 deletions src/usr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod deflate;
pub mod dhcp;
pub mod diff;
pub mod disk;
pub mod draw;
pub mod drop;
pub mod edit;
pub mod elf;
Expand Down
13 changes: 7 additions & 6 deletions src/usr/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ use alloc::vec::Vec;
use core::sync::atomic::{fence, Ordering};

// TODO: Scan /bin
const AUTOCOMPLETE_COMMANDS: [&str; 44] = [
const AUTOCOMPLETE_COMMANDS: [&str; 45] = [
"2048", "brainfuck", "calc", "chess", "copy", "date", "decode", "deflate",
"dhcp", "diff", "disk", "drop", "edit", "elf", "encode", "env", "goto",
"hash", "help", "hex", "host", "http", "httpd", "inflate", "install",
"keyboard", "life", "lisp", "list", "memory", "move", "net", "pci", "quit",
"read", "render", "shell", "socket", "spell", "tcp", "time", "user", "view",
"write",
"dhcp", "diff", "disk", "draw", "drop", "edit", "elf", "encode", "env",
"goto", "hash", "help", "hex", "host", "http", "httpd", "inflate",
"install", "keyboard", "life", "lisp", "list", "memory", "move", "net",
"pci", "quit", "read", "render", "shell", "socket", "spell", "tcp", "time",
"user", "view", "write",
];

struct Config {
Expand Down Expand Up @@ -528,6 +528,7 @@ fn dispatch(args: &[&str], config: &mut Config) -> Result<(), ExitCode> {
"dhcp" => usr::dhcp::main(args),
"diff" => usr::diff::main(args),
"disk" => usr::disk::main(args),
"draw" => usr::draw::main(args),
"drop" => usr::drop::main(args),
"edit" => usr::edit::main(args),
"elf" => usr::elf::main(args),
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载