feat(ux): change themes at runtime (#3559)
This commit is contained in:
parent
45501793d1
commit
e96491a3cf
12 changed files with 81 additions and 31 deletions
|
|
@ -215,7 +215,7 @@ pub fn start_client(
|
||||||
config.env.set_vars();
|
config.env.set_vars();
|
||||||
|
|
||||||
let palette = config
|
let palette = config
|
||||||
.theme_config(&config_options)
|
.theme_config(config_options.theme.as_ref())
|
||||||
.unwrap_or_else(|| os_input.load_palette());
|
.unwrap_or_else(|| os_input.load_palette());
|
||||||
|
|
||||||
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
|
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
|
||||||
|
|
@ -615,7 +615,7 @@ pub fn start_server_detached(
|
||||||
config.env.set_vars();
|
config.env.set_vars();
|
||||||
|
|
||||||
let palette = config
|
let palette = config
|
||||||
.theme_config(&config_options)
|
.theme_config(config_options.theme.as_ref())
|
||||||
.unwrap_or_else(|| os_input.load_palette());
|
.unwrap_or_else(|| os_input.load_palette());
|
||||||
|
|
||||||
let client_attributes = ClientAttributes {
|
let client_attributes = ClientAttributes {
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ use zellij_utils::{
|
||||||
plugins::PluginAliases,
|
plugins::PluginAliases,
|
||||||
},
|
},
|
||||||
ipc::{ClientAttributes, ExitReason, ServerToClientMsg},
|
ipc::{ClientAttributes, ExitReason, ServerToClientMsg},
|
||||||
|
shared::default_palette,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type ClientId = u16;
|
pub type ClientId = u16;
|
||||||
|
|
@ -267,6 +268,9 @@ impl SessionMetaData {
|
||||||
client_id,
|
client_id,
|
||||||
keybinds: Some(new_config.keybinds.clone()),
|
keybinds: Some(new_config.keybinds.clone()),
|
||||||
default_mode: new_config.options.default_mode,
|
default_mode: new_config.options.default_mode,
|
||||||
|
theme: new_config
|
||||||
|
.theme_config(new_config.options.theme.as_ref())
|
||||||
|
.or_else(|| Some(default_palette())),
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.senders
|
self.senders
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use zellij_utils::{
|
use zellij_utils::{
|
||||||
data::{ModeInfo, Style},
|
data::{ModeInfo, Palette, Style},
|
||||||
errors::prelude::*,
|
errors::prelude::*,
|
||||||
input::command::RunCommand,
|
input::command::RunCommand,
|
||||||
input::layout::{FloatingPaneLayout, Run, RunPluginOrAlias},
|
input::layout::{FloatingPaneLayout, Run, RunPluginOrAlias},
|
||||||
|
|
@ -913,4 +913,10 @@ impl FloatingPanes {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn update_pane_themes(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme;
|
||||||
|
for pane in self.panes.values_mut() {
|
||||||
|
pane.update_theme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2155,6 +2155,9 @@ impl Grid {
|
||||||
pub fn unlock_renders(&mut self) {
|
pub fn unlock_renders(&mut self) {
|
||||||
self.lock_renders = false;
|
self.lock_renders = false;
|
||||||
}
|
}
|
||||||
|
pub fn update_theme(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Perform for Grid {
|
impl Perform for Grid {
|
||||||
|
|
|
||||||
|
|
@ -675,6 +675,12 @@ impl Pane for PluginPane {
|
||||||
self.pane_name = String::from_utf8_lossy(&buf).to_string();
|
self.pane_name = String::from_utf8_lossy(&buf).to_string();
|
||||||
self.set_should_render(true);
|
self.set_should_render(true);
|
||||||
}
|
}
|
||||||
|
fn update_theme(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme.clone();
|
||||||
|
for grid in self.grids.values_mut() {
|
||||||
|
grid.update_theme(theme.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PluginPane {
|
impl PluginPane {
|
||||||
|
|
|
||||||
|
|
@ -790,6 +790,14 @@ impl Pane for TerminalPane {
|
||||||
run_command.clone()
|
run_command.clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
fn update_theme(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme.clone();
|
||||||
|
self.grid.update_theme(theme);
|
||||||
|
if self.banner.is_some() {
|
||||||
|
// we do this so that the banner will be updated with the new theme colors
|
||||||
|
self.render_first_run_banner();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalPane {
|
impl TerminalPane {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use stacked_panes::StackedPanes;
|
use stacked_panes::StackedPanes;
|
||||||
use zellij_utils::{
|
use zellij_utils::{
|
||||||
data::{Direction, ModeInfo, PaneInfo, ResizeStrategy, Style},
|
data::{Direction, ModeInfo, Palette, PaneInfo, ResizeStrategy, Style},
|
||||||
errors::prelude::*,
|
errors::prelude::*,
|
||||||
input::{
|
input::{
|
||||||
command::RunCommand,
|
command::RunCommand,
|
||||||
|
|
@ -1766,6 +1766,12 @@ impl TiledPanes {
|
||||||
}
|
}
|
||||||
pane_infos
|
pane_infos
|
||||||
}
|
}
|
||||||
|
pub fn update_pane_themes(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme;
|
||||||
|
for pane in self.panes.values_mut() {
|
||||||
|
pane.update_theme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::borrowed_box)]
|
#[allow(clippy::borrowed_box)]
|
||||||
|
|
|
||||||
|
|
@ -93,23 +93,6 @@ pub(crate) fn route_action(
|
||||||
},
|
},
|
||||||
Action::SwitchToMode(mode) => {
|
Action::SwitchToMode(mode) => {
|
||||||
let attrs = &client_attributes;
|
let attrs = &client_attributes;
|
||||||
// TODO: use the palette from the client and remove it from the server os api
|
|
||||||
// this is left here as a stop gap measure until we shift some code around
|
|
||||||
// to allow for this
|
|
||||||
// TODO: Need access to `ClientAttributes` here
|
|
||||||
senders
|
|
||||||
.send_to_plugin(PluginInstruction::Update(vec![(
|
|
||||||
None,
|
|
||||||
Some(client_id),
|
|
||||||
Event::ModeUpdate(get_mode_info(
|
|
||||||
mode,
|
|
||||||
attrs,
|
|
||||||
capabilities,
|
|
||||||
&client_keybinds,
|
|
||||||
Some(default_mode),
|
|
||||||
)),
|
|
||||||
)]))
|
|
||||||
.with_context(err_context)?;
|
|
||||||
senders
|
senders
|
||||||
.send_to_server(ServerInstruction::ChangeMode(client_id, mode))
|
.send_to_server(ServerInstruction::ChangeMode(client_id, mode))
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,7 @@ pub enum ScreenInstruction {
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Option<Keybinds>,
|
||||||
default_mode: Option<InputMode>,
|
default_mode: Option<InputMode>,
|
||||||
|
theme: Option<Palette>,
|
||||||
},
|
},
|
||||||
RerunCommandPane(u32), // u32 - terminal pane id
|
RerunCommandPane(u32), // u32 - terminal pane id
|
||||||
}
|
}
|
||||||
|
|
@ -1735,11 +1736,13 @@ impl Screen {
|
||||||
if mode_info.session_name.as_ref() != Some(&self.session_name) {
|
if mode_info.session_name.as_ref() != Some(&self.session_name) {
|
||||||
mode_info.session_name = Some(self.session_name.clone());
|
mode_info.session_name = Some(self.session_name.clone());
|
||||||
}
|
}
|
||||||
let previous_mode = self
|
|
||||||
|
let previous_mode_info = self
|
||||||
.mode_info
|
.mode_info
|
||||||
.get(&client_id)
|
.get(&client_id)
|
||||||
.unwrap_or(&self.default_mode_info)
|
.unwrap_or(&self.default_mode_info);
|
||||||
.mode;
|
let previous_mode = previous_mode_info.mode;
|
||||||
|
mode_info.style = previous_mode_info.style;
|
||||||
|
|
||||||
let err_context = || {
|
let err_context = || {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -2183,10 +2186,22 @@ impl Screen {
|
||||||
&mut self,
|
&mut self,
|
||||||
new_keybinds: Option<Keybinds>,
|
new_keybinds: Option<Keybinds>,
|
||||||
new_default_mode: Option<InputMode>,
|
new_default_mode: Option<InputMode>,
|
||||||
|
theme: Option<Palette>,
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let should_update_mode_info =
|
||||||
|
new_keybinds.is_some() || new_default_mode.is_some() || theme.is_some();
|
||||||
|
|
||||||
|
// themes are currently global and not per-client
|
||||||
|
if let Some(theme) = theme {
|
||||||
|
self.default_mode_info.update_theme(theme);
|
||||||
|
for tab in self.tabs.values_mut() {
|
||||||
|
tab.update_theme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// client specific configuration
|
||||||
if self.connected_clients_contains(&client_id) {
|
if self.connected_clients_contains(&client_id) {
|
||||||
let should_update_mode_info = new_keybinds.is_some() || new_default_mode.is_some();
|
|
||||||
let mode_info = self
|
let mode_info = self
|
||||||
.mode_info
|
.mode_info
|
||||||
.entry(client_id)
|
.entry(client_id)
|
||||||
|
|
@ -2197,16 +2212,22 @@ impl Screen {
|
||||||
if let Some(new_default_mode) = new_default_mode {
|
if let Some(new_default_mode) = new_default_mode {
|
||||||
mode_info.update_default_mode(new_default_mode);
|
mode_info.update_default_mode(new_default_mode);
|
||||||
}
|
}
|
||||||
|
if let Some(theme) = theme {
|
||||||
|
mode_info.update_theme(theme);
|
||||||
|
}
|
||||||
if should_update_mode_info {
|
if should_update_mode_info {
|
||||||
for tab in self.tabs.values_mut() {
|
for tab in self.tabs.values_mut() {
|
||||||
tab.change_mode_info(mode_info.clone(), client_id);
|
tab.change_mode_info(mode_info.clone(), client_id);
|
||||||
tab.mark_active_pane_for_rerender(client_id);
|
tab.mark_active_pane_for_rerender(client_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_update_mode_info {
|
||||||
|
for tab in self.tabs.values_mut() {
|
||||||
tab.update_input_modes()?;
|
tab.update_input_modes()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log::error!("Could not find client_id {client_id} to rebind keys");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn unblock_input(&self) -> Result<()> {
|
fn unblock_input(&self) -> Result<()> {
|
||||||
|
|
@ -4082,9 +4103,10 @@ pub(crate) fn screen_thread_main(
|
||||||
client_id,
|
client_id,
|
||||||
keybinds,
|
keybinds,
|
||||||
default_mode,
|
default_mode,
|
||||||
|
theme,
|
||||||
} => {
|
} => {
|
||||||
screen
|
screen
|
||||||
.reconfigure_mode_info(keybinds, default_mode, client_id)
|
.reconfigure_mode_info(keybinds, default_mode, theme, client_id)
|
||||||
.non_fatal();
|
.non_fatal();
|
||||||
},
|
},
|
||||||
ScreenInstruction::RerunCommandPane(terminal_pane_id) => {
|
ScreenInstruction::RerunCommandPane(terminal_pane_id) => {
|
||||||
|
|
|
||||||
|
|
@ -492,6 +492,7 @@ pub trait Pane {
|
||||||
fn rerun(&mut self) -> Option<RunCommand> {
|
fn rerun(&mut self) -> Option<RunCommand> {
|
||||||
None
|
None
|
||||||
} // only relevant to terminal panes
|
} // only relevant to terminal panes
|
||||||
|
fn update_theme(&mut self, _theme: Palette) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -3951,6 +3952,14 @@ impl Tab {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn update_theme(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme;
|
||||||
|
self.floating_panes.update_pane_themes(theme);
|
||||||
|
self.tiled_panes.update_pane_themes(theme);
|
||||||
|
for (_, pane) in self.suppressed_panes.values_mut() {
|
||||||
|
pane.update_theme(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pane_info_for_pane(pane_id: &PaneId, pane: &Box<dyn Pane>) -> PaneInfo {
|
pub fn pane_info_for_pane(pane_id: &PaneId, pane: &Box<dyn Pane>) -> PaneInfo {
|
||||||
|
|
|
||||||
|
|
@ -1175,6 +1175,9 @@ impl ModeInfo {
|
||||||
pub fn update_default_mode(&mut self, new_default_mode: InputMode) {
|
pub fn update_default_mode(&mut self, new_default_mode: InputMode) {
|
||||||
self.base_mode = Some(new_default_mode);
|
self.base_mode = Some(new_default_mode);
|
||||||
}
|
}
|
||||||
|
pub fn update_theme(&mut self, theme: Palette) {
|
||||||
|
self.style.colors = theme;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||||
|
|
|
||||||
|
|
@ -163,8 +163,8 @@ impl TryFrom<&CliArgs> for Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn theme_config(&self, opts: &Options) -> Option<Palette> {
|
pub fn theme_config(&self, theme_name: Option<&String>) -> Option<Palette> {
|
||||||
match &opts.theme {
|
match &theme_name {
|
||||||
Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette),
|
Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette),
|
||||||
None => self.themes.get_theme("default").map(|theme| theme.palette),
|
None => self.themes.get_theme("default").map(|theme| theme.palette),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue