Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature(overlay): add initial overlay work #871

Merged
merged 2 commits into from
Nov 15, 2021
Merged
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
2 changes: 1 addition & 1 deletion default-plugins/status-bar/src/first_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
colored_elements,
separator,
),
InputMode::Normal => key_indicators(
InputMode::Normal | InputMode::Prompt => key_indicators(
max_len,
&[
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
Expand Down
4 changes: 2 additions & 2 deletions zellij-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ use zellij_utils::{
setup::get_default_data_dir,
};

pub(crate) type ClientId = u16;
pub type ClientId = u16;

/// Instructions related to server-side application
#[derive(Debug, Clone)]
pub(crate) enum ServerInstruction {
pub enum ServerInstruction {
NewClient(
ClientAttributes,
Box<CliArgs>,
Expand Down
22 changes: 22 additions & 0 deletions zellij-server/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,28 @@ fn route_action(
.send_to_screen(ScreenInstruction::Copy(client_id))
.unwrap();
}
Action::Confirm => {
session
.senders
.send_to_screen(ScreenInstruction::ConfirmPrompt(client_id))
.unwrap();
}
Action::Deny => {
session
.senders
.send_to_screen(ScreenInstruction::DenyPrompt(client_id))
.unwrap();
}
#[allow(clippy::single_match)]
Action::SkipConfirm(action) => match *action {
Action::Quit => {
to_server
.send(ServerInstruction::ClientExit(client_id))
.unwrap();
should_break = true;
}
_ => {}
},
Action::NoOp => {}
}
should_break
Expand Down
18 changes: 17 additions & 1 deletion zellij-server/src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
pty::{ClientOrTabIndex, PtyInstruction, VteBytes},
tab::{Output, Tab},
thread_bus::Bus,
ui::overlay::{Overlay, OverlayWindow},
wasm_vm::PluginInstruction,
ClientId, ServerInstruction,
};
Expand All @@ -24,7 +25,7 @@ use zellij_utils::{

/// Instructions that can be sent to the [`Screen`].
#[derive(Debug, Clone)]
pub(crate) enum ScreenInstruction {
pub enum ScreenInstruction {
PtyBytes(RawFd, VteBytes),
Render,
NewPane(PaneId, ClientOrTabIndex),
Expand Down Expand Up @@ -84,6 +85,10 @@ pub(crate) enum ScreenInstruction {
Copy(ClientId),
AddClient(ClientId),
RemoveClient(ClientId),
AddOverlay(Overlay, ClientId),
RemoveOverlay(ClientId),
ConfirmPrompt(ClientId),
DenyPrompt(ClientId),
}

impl From<&ScreenInstruction> for ScreenContext {
Expand Down Expand Up @@ -154,6 +159,10 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::ToggleTab(..) => ScreenContext::ToggleTab,
ScreenInstruction::AddClient(..) => ScreenContext::AddClient,
ScreenInstruction::RemoveClient(..) => ScreenContext::RemoveClient,
ScreenInstruction::AddOverlay(..) => ScreenContext::AddOverlay,
ScreenInstruction::RemoveOverlay(..) => ScreenContext::RemoveOverlay,
ScreenInstruction::ConfirmPrompt(..) => ScreenContext::ConfirmPrompt,
ScreenInstruction::DenyPrompt(..) => ScreenContext::DenyPrompt,
}
}
}
Expand All @@ -169,6 +178,8 @@ pub(crate) struct Screen {
tabs: BTreeMap<usize, Tab>,
/// The full size of this [`Screen`].
size: Size,
/// The overlay that is drawn on top of [`Pane`]'s', [`Tab`]'s and the [`Screen`]
_overlay: OverlayWindow,
/// The indices of this [`Screen`]'s active [`Tab`]s.
active_tab_indices: BTreeMap<ClientId, usize>,
tab_history: BTreeMap<ClientId, Vec<usize>>,
Expand All @@ -193,6 +204,7 @@ impl Screen {
colors: client_attributes.palette,
active_tab_indices: BTreeMap::new(),
tabs: BTreeMap::new(),
_overlay: OverlayWindow::default(),
tab_history: BTreeMap::new(),
mode_info,
draw_pane_frames,
Expand Down Expand Up @@ -1088,6 +1100,10 @@ pub(crate) fn screen_thread_main(

screen.render();
}
ScreenInstruction::AddOverlay(_, _) => {}
ScreenInstruction::RemoveOverlay(_) => {}
ScreenInstruction::ConfirmPrompt(_) => {}
ScreenInstruction::DenyPrompt(_) => {}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions zellij-server/src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod boundaries;
pub mod overlay;
pub mod pane_boundaries_frame;
pub mod pane_resizer;
104 changes: 104 additions & 0 deletions zellij-server/src/ui/overlay/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! This module handles the overlay's over the [`Screen`]
//!
//! They consist of:
//!
//! prompt's:
//!
//! notification's:

pub mod prompt;

use crate::ServerInstruction;
use zellij_utils::pane_size::Size;

#[derive(Clone, Debug)]
pub struct Overlay {
pub overlay_type: OverlayType,
}

pub trait Overlayable {
/// Generates vte_output that can be passed into
/// the `render()` function
fn generate_overlay(&self, size: Size) -> String;
}

#[derive(Clone, Debug)]
struct Padding {
rows: usize,
cols: usize,
}

#[derive(Clone, Debug)]
pub enum OverlayType {
Prompt(prompt::Prompt),
}

impl Overlayable for OverlayType {
fn generate_overlay(&self, size: Size) -> String {
match &self {
OverlayType::Prompt(prompt) => prompt.generate_overlay(size),
}
}
}

/// Entrypoint from [`Screen`], which holds the context in which
/// the overlays are being rendered.
/// The most recent overlays draw over the previous overlays.
#[derive(Clone, Debug)]
pub struct OverlayWindow {
pub overlay_stack: Vec<Overlay>,
}

impl Default for OverlayWindow {
fn default() -> Self {
Self {
overlay_stack: vec![],
}
}
}

impl Overlayable for OverlayWindow {
fn generate_overlay(&self, size: Size) -> String {
let mut output = String::new();
//let clear_display = "\u{1b}[2J";
//output.push_str(&clear_display);
for overlay in &self.overlay_stack {
let vte_output = overlay.generate_overlay(size);
output.push_str(&vte_output);
}
output
}
}

impl Overlay {
pub fn prompt_confirm(self) -> Option<Box<ServerInstruction>> {
match self.overlay_type {
OverlayType::Prompt(p) => p.confirm(),
}
}
pub fn prompt_deny(self) -> Option<Box<ServerInstruction>> {
match self.overlay_type {
OverlayType::Prompt(p) => p.deny(),
}
}
}

impl Overlayable for Overlay {
fn generate_overlay(&self, size: Size) -> String {
self.overlay_type.generate_overlay(size)
}
}

impl Overlay {
pub fn new(overlay_type: OverlayType) -> Self {
Self { overlay_type }
}

fn pad_cols(output: &mut String, cols: usize) {
if let Some(padding) = cols.checked_sub(output.len()) {
for _ in 0..padding {
output.push(' ');
}
}
}
}
55 changes: 55 additions & 0 deletions zellij-server/src/ui/overlay/prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use zellij_utils::pane_size::Size;

use super::{Overlay, OverlayType, Overlayable};
use crate::{ClientId, ServerInstruction};

#[derive(Clone, Debug)]
pub struct Prompt {
pub message: String,
on_confirm: Option<Box<ServerInstruction>>,
on_deny: Option<Box<ServerInstruction>>,
}

impl Prompt {
pub fn new(
message: String,
on_confirm: Option<Box<ServerInstruction>>,
on_deny: Option<Box<ServerInstruction>>,
) -> Self {
Self {
message,
on_confirm,
on_deny,
}
}
pub fn confirm(self) -> Option<Box<ServerInstruction>> {
self.on_confirm
}
pub fn deny(self) -> Option<Box<ServerInstruction>> {
self.on_deny
}
}

impl Overlayable for Prompt {
fn generate_overlay(&self, size: Size) -> String {
let mut output = String::new();
let rows = size.rows;
let mut vte_output = self.message.clone();
Overlay::pad_cols(&mut vte_output, size.cols);
for (x, h) in vte_output.chars().enumerate() {
output.push_str(&format!("\u{1b}[{};{}H\u{1b}[48;5;238m{}", rows, x + 1, h,));
}
output
}
}

pub fn _generate_quit_prompt(client_id: ClientId) -> Overlay {
let prompt = Prompt::new(
(" Do you want to quit zellij? [Y]es / [N]o").to_string(),
Some(Box::new(ServerInstruction::ClientExit(client_id))),
None,
);
Overlay {
overlay_type: OverlayType::Prompt(prompt),
}
}
4 changes: 4 additions & 0 deletions zellij-tile/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ pub enum InputMode {
/// `Move` mode allows moving the different existing panes within a tab
#[serde(alias = "move")]
Move,
/// `Prompt` mode allows interacting with active prompts.
#[serde(alias = "prompt")]
Prompt,
}

impl Default for InputMode {
Expand Down Expand Up @@ -129,6 +132,7 @@ impl FromStr for InputMode {
"renametab" => Ok(InputMode::RenameTab),
"session" => Ok(InputMode::Session),
"move" => Ok(InputMode::Move),
"prompt" => Ok(InputMode::Prompt),
e => Err(e.to_string().into()),
}
}
Expand Down
4 changes: 4 additions & 0 deletions zellij-utils/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ pub enum ScreenContext {
ToggleTab,
AddClient,
RemoveClient,
AddOverlay,
RemoveOverlay,
ConfirmPrompt,
DenyPrompt,
}

/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
Expand Down
6 changes: 6 additions & 0 deletions zellij-utils/src/input/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ pub enum Action {
MouseRelease(Position),
MouseHold(Position),
Copy,
/// Confirm a prompt
Confirm,
/// Deny a prompt
Deny,
/// Confirm an action that invokes a prompt automatically
SkipConfirm(Box<Action>),
}

impl From<OnForceClose> for Action {
Expand Down
2 changes: 1 addition & 1 deletion zellij-utils/src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn get_mode_info(
capabilities: PluginCapabilities,
) -> ModeInfo {
let keybinds = match mode {
InputMode::Normal | InputMode::Locked => Vec::new(),
InputMode::Normal | InputMode::Locked | InputMode::Prompt => Vec::new(),
InputMode::Resize => vec![
("←↓↑→".to_string(), "Resize".to_string()),
("+-".to_string(), "Increase/Decrease size".to_string()),
Expand Down