mprocs 0.9.3

TUI for running multiple processes
Documentation
use crate::color;
use crate::console::state::ConsoleState;
use crate::console::views::frame::draw_frame;
use crate::console::views::pane::Pane;
use crate::kernel::task::TaskStatus;
use crate::term::Grid;
use crate::term::attrs::Attrs;
use crate::term::grid::Rect;
use crate::term::scroll_offset;

pub struct ProcsPane;

impl Pane for ProcsPane {
  fn render(
    &mut self,
    grid: &mut Grid,
    area: Rect,
    state: &mut ConsoleState,
    focused: bool,
  ) {
    draw_frame(grid, area, " Processes ", focused);
    if area.width < 2 || area.height < 2 {
      return;
    }

    let inner = area.inner(1);
    if state.tasks.is_empty() {
      grid.draw_text(
        area.inner((1, 2)),
        "No tasks",
        Attrs::default().fg(color!("#aaaaaa")),
      );
      return;
    }

    let max_rows = inner.height as usize;
    let start = scroll_offset(state.selected, state.tasks.len(), max_rows);

    for (i, task) in state.tasks.iter().enumerate().skip(start).take(max_rows) {
      let Some(row) = inner.row((i - start) as u16) else {
        break;
      };
      let is_selected = i == state.selected;
      let bg = if is_selected {
        color!("#303030")
      } else {
        color!("#111111")
      };

      let (status_col, path_col) = row.split_v(2);

      let (status_char, status_color) = match task.status {
        TaskStatus::Running => ("", color!("#4ec55e")),
        TaskStatus::NotStarted => ("", color!("#888888")),
        TaskStatus::Exited(0) => ("", color!("#5a8ee0")),
        TaskStatus::Exited(_) => ("", color!("#e05a5a")),
      };
      grid.draw_line(
        status_col,
        status_char,
        Attrs::default().fg(status_color).bg(bg),
      );
      grid.draw_line(
        path_col,
        &task.path,
        Attrs::default().fg(color!("#e0e0e0")).bg(bg),
      );
    }
  }
}