Skip to content

Commit

Permalink
Add ANSI OSC color palette support (#566)
Browse files Browse the repository at this point in the history
* Refactor vga palette code

* Add osc dispatch to handle ansi palette

* Add warning macro

* Deprecate vga set palette command

* Add shell script to set palettes

* Remove TODO

* Add new TODO comments

* Add reset sequence

* Add cursor edge checks
  • Loading branch information
vinc authored Jan 8, 2024
1 parent 1de69e0 commit a9eb6f9
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 31 deletions.
16 changes: 16 additions & 0 deletions dsk/ini/palettes/gruvbox-dark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
print "\e]P0282828\e[1A" # Black
print "\e]P1458588\e[1A" # Blue
print "\e]P298971A\e[1A" # Green
print "\e]P3689D6A\e[1A" # Cyan
print "\e]P4CC241D\e[1A" # Red
print "\e]P5B16286\e[1A" # Magenta
print "\e]P6D79921\e[1A" # Brown (Dark Yellow)
print "\e]P7EBDBB2\e[1A" # Light Gray
print "\e]P8A89984\e[1A" # Dark Gray (Gray)
print "\e]P983a598\e[1A" # Light Blue
print "\e]PAB8BB26\e[1A" # Light Green
print "\e]PB8EC07C\e[1A" # Light Cyan
print "\e]PCFB4934\e[1A" # Light Red
print "\e]PDD3869B\e[1A" # Pink (Light Magenta)
print "\e]PEFABD2F\e[1A" # Yellow (Light Yellow)
print "\e]PFFBF1C7\e[1A" # White
16 changes: 16 additions & 0 deletions dsk/ini/palettes/gruvbox-light.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
print "\e]P0FBF1C7\e[1A" # Black
print "\e]P1458588\e[1A" # Blue
print "\e]P298971A\e[1A" # Green
print "\e]P3689D6A\e[1A" # Cyan
print "\e]P4CC241D\e[1A" # Red
print "\e]P5B16286\e[1A" # Magenta
print "\e]P6D79921\e[1A" # Brown (Dark Yellow)
print "\e]P73C3836\e[1A" # Light Gray
print "\e]P87C6F64\e[1A" # Dark Gray (Gray)
print "\e]P9076678\e[1A" # Light Blue
print "\e]PA79740E\e[1A" # Light Green
print "\e]PB427B58\e[1A" # Light Cyan
print "\e]PC9D0006\e[1A" # Light Red
print "\e]PD8F3F71\e[1A" # Pink (Light Magenta)
print "\e]PEB57614\e[1A" # Yellow (Light Yellow)
print "\e]PF282828\e[1A" # White
9 changes: 9 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ macro_rules! error {
});
}

#[macro_export]
macro_rules! warning {
($($arg:tt)*) => ({
let csi_color = $crate::api::console::Style::color("Yellow");
let csi_reset = $crate::api::console::Style::reset();
eprintln!("{}Warning:{} {}", csi_color, csi_reset, format_args!($($arg)*));
});
}

pub mod allocator;
pub mod clock;
pub mod console;
Expand Down
2 changes: 2 additions & 0 deletions src/api/vga/palette.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use alloc::vec::Vec;
use core::convert::TryInto;

// TODO: Move this to kernel after removing the `vga set palette` command
pub struct Palette {
pub colors: [(u8, u8, u8); 16]
}
Expand Down Expand Up @@ -30,6 +31,7 @@ impl Palette {
}
}

// TODO: Remove this
pub fn from_csv(s: &str) -> Result<Palette, ()> {
let colors: Vec<_> = s.split('\n').filter_map(|line| {
let line = line.split('#').next().unwrap(); // Remove comments
Expand Down
67 changes: 44 additions & 23 deletions src/sys/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use crate::api::vga::{Color, Palette};
use crate::api::vga::color;
use crate::sys;

use alloc::string::String;
use bit_field::BitField;
use core::cmp;
use core::fmt;
use core::fmt::Write;
use lazy_static::lazy_static;
Expand Down Expand Up @@ -244,18 +246,16 @@ impl Writer {
}
}

pub fn set_palette(&mut self, palette: Palette) {
pub fn set_palette(&mut self, i: usize, r: u8, g: u8, b: u8) {
let mut addr: Port<u8> = Port::new(DAC_ADDR_WRITE_MODE_REG);
let mut data: Port<u8> = Port::new(DAC_DATA_REG);
for (i, (r, g, b)) in palette.colors.iter().enumerate() {
if i < 16 {
let reg = color::from_index(i).to_vga_reg();
unsafe {
addr.write(reg);
data.write(vga_color(*r));
data.write(vga_color(*g));
data.write(vga_color(*b));
}
if i < 16 {
let reg = color::from_index(i).to_vga_reg();
unsafe {
addr.write(reg);
data.write(vga_color(r));
data.write(vga_color(g));
data.write(vga_color(b));
}
}
}
Expand Down Expand Up @@ -303,36 +303,32 @@ impl Perform for Writer {
for param in params.iter() {
n = param[0] as usize;
}
// TODO: Don't go past edge
self.writer[1] -= n;
self.cursor[1] -= n;
self.writer[1] = self.writer[1].saturating_sub(n);
self.cursor[1] = self.cursor[1].saturating_sub(n);
},
'B' => { // Cursor Down
let mut n = 1;
for param in params.iter() {
n = param[0] as usize;
}
// TODO: Don't go past edge
self.writer[1] += n;
self.cursor[1] += n;
self.writer[1] = cmp::min(self.writer[1] + n, BUFFER_HEIGHT - 1);
self.cursor[1] = cmp::min(self.cursor[1] + n, BUFFER_HEIGHT - 1);
},
'C' => { // Cursor Forward
let mut n = 1;
for param in params.iter() {
n = param[0] as usize;
}
// TODO: Don't go past edge
self.writer[0] += n;
self.cursor[0] += n;
self.writer[0] = cmp::min(self.writer[0] + n, BUFFER_WIDTH - 1);
self.cursor[0] = cmp::min(self.cursor[0] + n, BUFFER_WIDTH - 1);
},
'D' => { // Cursor Backward
let mut n = 1;
for param in params.iter() {
n = param[0] as usize;
}
// TODO: Don't go past edge
self.writer[0] -= n;
self.cursor[0] -= n;
self.writer[0] = self.writer[0].saturating_sub(n);
self.cursor[0] = self.cursor[0].saturating_sub(n);
},
'G' => { // Cursor Horizontal Absolute
let (_, y) = self.cursor_position();
Expand Down Expand Up @@ -411,6 +407,28 @@ impl Perform for Writer {
_ => {},
}
}

fn osc_dispatch(&mut self, params: &[&[u8]], _: bool) {
if params.len() == 1 {
let s = String::from_utf8_lossy(params[0]);
match s.chars().next() {
Some('P') if s.len() == 8 => {
let i = usize::from_str_radix(&s[1..2], 16).unwrap_or(0);
let r = u8::from_str_radix(&s[2..4], 16).unwrap_or(0);
let g = u8::from_str_radix(&s[4..6], 16).unwrap_or(0);
let b = u8::from_str_radix(&s[6..8], 16).unwrap_or(0);
self.set_palette(i, r, g, b);
}
Some('R') => {
let palette = Palette::default();
for (i, (r, g, b)) in palette.colors.iter().enumerate() {
self.set_palette(i, *r, *g, *b);
}
}
_ => {}
}
}
}
}

impl fmt::Write for Writer {
Expand Down Expand Up @@ -467,9 +485,12 @@ pub fn set_font(font: &Font) {
})
}

// TODO: Remove this
pub fn set_palette(palette: Palette) {
interrupts::without_interrupts(|| {
WRITER.lock().set_palette(palette)
for (i, (r, g, b)) in palette.colors.iter().enumerate() {
WRITER.lock().set_palette(i, *r, *g, *b);
}
})
}

Expand Down
4 changes: 2 additions & 2 deletions src/usr/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ pub fn copy_files(verbose: bool) {
copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt"), verbose);

create_dir("/ini/palettes", verbose);
copy_file("/ini/palettes/gruvbox-dark.csv", include_bytes!("../../dsk/ini/palettes/gruvbox-dark.csv"), verbose);
copy_file("/ini/palettes/gruvbox-light.csv", include_bytes!("../../dsk/ini/palettes/gruvbox-light.csv"), verbose);
copy_file("/ini/palettes/gruvbox-dark.sh", include_bytes!("../../dsk/ini/palettes/gruvbox-dark.sh"), verbose);
copy_file("/ini/palettes/gruvbox-light.sh", include_bytes!("../../dsk/ini/palettes/gruvbox-light.sh"), verbose);

create_dir("/ini/fonts", verbose);
//copy_file("/ini/fonts/lat15-terminus-8x16.psf", include_bytes!("../../dsk/ini/fonts/lat15-terminus-8x16.psf"), verbose);
Expand Down
8 changes: 2 additions & 6 deletions src/usr/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::api::fs;
use crate::api::vga::palette;
use crate::api::process::ExitCode;

// TODO: Remove this command when everything can be done from userspace
pub fn main(args: &[&str]) -> Result<(), ExitCode> {
if args.len() == 1 {
help();
Expand All @@ -30,15 +31,10 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
Err(ExitCode::Failure)
}
} else if args.len() == 4 && args[2] == "palette" {
warning!("Use ANSI OSC palette sequence");
if let Ok(csv) = fs::read_to_string(args[3]) {
if let Ok(palette) = palette::from_csv(&csv) {
sys::vga::set_palette(palette);
// TODO: Instead of calling a kernel function we could
// use the following ANSI OSC command to set a palette:
// for (i, r, g, b) in palette.colors {
// print!("\x1b]P{:x}{:x}{:x}{:x}", i, r, g, b);
// }
// And "ESC]R" to reset a palette.
Ok(())
} else {
error!("Could not parse palette file");
Expand Down

0 comments on commit a9eb6f9

Please sign in to comment.