Merge pull request #479 from a-kenji/simple-font-ui

Add Option for Simplified Layout
This commit is contained in:
a-kenji 2021-05-11 22:09:33 +02:00 committed by GitHub
commit 38b8f64ae6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 253 additions and 91 deletions

View File

@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Add more functionality to unbinding the default keybindings (https://github.com/zellij-org/zellij/pull/468)
* Terminal compatibility: fix support for CSI subparameters (https://github.com/zellij-org/zellij/pull/469)
* Move the sync command to tab mode (https://github.com/zellij-org/zellij/pull/412)
* Add support for requesting a simpler layout from plugins, move `clean` flag from `options` to `setup` (https://github.com/zellij-org/zellij/pull/479)
* Fix exit code of `dump-default-config` (https://github.com/zellij-org/zellij/pull/480)
* Feature: Switch tabs using `Alt + h/l` in normal mode if there are no panes in the direction (https://github.com/zellij-org/zellij/pull/471)
* Terminal Compatibility: various behaviour fixes (https://github.com/zellij-org/zellij/pull/486)

View File

@ -36,6 +36,11 @@ cargo install zellij
Or you can download a prebuilt binary from our [Releases](https://github.com/zellij-org/zellij/releases).
As the default plugins make use of characters that are mostly only found in [nerdfonts](https://www.nerdfonts.com/),
you get the best experience either with installing nerdfonts, or telling the plugins that you request a ui, that
does not rely on such characters with `zellij options --simplified-ui`, or putting `simplified_ui: true` in the
config file.
## How do I hack on it? (Contributing)
* Clone the project
* Install cargo-make with `cargo install --force cargo-make`

View File

@ -2,7 +2,7 @@ use ansi_term::ANSIStrings;
use zellij_tile::prelude::*;
use crate::color_elements;
use crate::{ColoredElements, LinePart, ARROW_SEPARATOR};
use crate::{ColoredElements, LinePart};
struct CtrlKeyShortcut {
mode: CtrlKeyMode,
@ -63,13 +63,18 @@ impl CtrlKeyShortcut {
}
}
fn unselected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) -> LinePart {
let prefix_separator = palette.unselected_prefix_separator.paint(ARROW_SEPARATOR);
fn unselected_mode_shortcut(
letter: char,
text: &str,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let prefix_separator = palette.unselected_prefix_separator.paint(separator);
let char_left_separator = palette.unselected_char_left_separator.paint(" <");
let char_shortcut = palette.unselected_char_shortcut.paint(letter.to_string());
let char_right_separator = palette.unselected_char_right_separator.paint(">");
let styled_text = palette.unselected_styled_text.paint(format!("{} ", text));
let suffix_separator = palette.unselected_suffix_separator.paint(ARROW_SEPARATOR);
let suffix_separator = palette.unselected_suffix_separator.paint(separator);
LinePart {
part: ANSIStrings(&[
prefix_separator,
@ -84,13 +89,18 @@ fn unselected_mode_shortcut(letter: char, text: &str, palette: ColoredElements)
}
}
fn selected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) -> LinePart {
let prefix_separator = palette.selected_prefix_separator.paint(ARROW_SEPARATOR);
fn selected_mode_shortcut(
letter: char,
text: &str,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let prefix_separator = palette.selected_prefix_separator.paint(separator);
let char_left_separator = palette.selected_char_left_separator.paint(" <".to_string());
let char_shortcut = palette.selected_char_shortcut.paint(format!("{}", letter));
let char_right_separator = palette.selected_char_right_separator.paint(">".to_string());
let styled_text = palette.selected_styled_text.paint(format!("{} ", text));
let suffix_separator = palette.selected_suffix_separator.paint(ARROW_SEPARATOR);
let suffix_separator = palette.selected_suffix_separator.paint(separator);
LinePart {
part: ANSIStrings(&[
prefix_separator,
@ -105,69 +115,89 @@ fn selected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) ->
}
}
fn disabled_mode_shortcut(text: &str, palette: ColoredElements) -> LinePart {
let prefix_separator = palette.disabled_prefix_separator.paint(ARROW_SEPARATOR);
fn disabled_mode_shortcut(text: &str, palette: ColoredElements, separator: &str) -> LinePart {
let prefix_separator = palette.disabled_prefix_separator.paint(separator);
let styled_text = palette.disabled_styled_text.paint(format!("{} ", text));
let suffix_separator = palette.disabled_suffix_separator.paint(ARROW_SEPARATOR);
let suffix_separator = palette.disabled_suffix_separator.paint(separator);
LinePart {
part: format!("{}{}{}", prefix_separator, styled_text, suffix_separator),
len: text.chars().count() + 2 + 1, // 2 for the arrows, 1 for the padding in the end
}
}
fn selected_mode_shortcut_single_letter(letter: char, palette: ColoredElements) -> LinePart {
fn selected_mode_shortcut_single_letter(
letter: char,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let char_shortcut_text = format!(" {} ", letter);
let len = char_shortcut_text.chars().count() + 4; // 2 for the arrows, 2 for the padding
let prefix_separator = palette
.selected_single_letter_prefix_separator
.paint(ARROW_SEPARATOR);
.paint(separator);
let char_shortcut = palette
.selected_single_letter_char_shortcut
.paint(char_shortcut_text);
let suffix_separator = palette
.selected_single_letter_suffix_separator
.paint(ARROW_SEPARATOR);
.paint(separator);
LinePart {
part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(),
len,
}
}
fn unselected_mode_shortcut_single_letter(letter: char, palette: ColoredElements) -> LinePart {
fn unselected_mode_shortcut_single_letter(
letter: char,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let char_shortcut_text = format!(" {} ", letter);
let len = char_shortcut_text.chars().count() + 4; // 2 for the arrows, 2 for the padding
let prefix_separator = palette
.unselected_single_letter_prefix_separator
.paint(ARROW_SEPARATOR);
.paint(separator);
let char_shortcut = palette
.unselected_single_letter_char_shortcut
.paint(char_shortcut_text);
let suffix_separator = palette
.unselected_single_letter_suffix_separator
.paint(ARROW_SEPARATOR);
.paint(separator);
LinePart {
part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(),
len,
}
}
fn full_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart {
fn full_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements, separator: &str) -> LinePart {
let full_text = key.full_text();
let letter_shortcut = key.letter_shortcut();
match key.mode {
CtrlKeyMode::Unselected => {
unselected_mode_shortcut(letter_shortcut, &format!(" {}", full_text), palette)
}
CtrlKeyMode::Selected => {
selected_mode_shortcut(letter_shortcut, &format!(" {}", full_text), palette)
}
CtrlKeyMode::Disabled => {
disabled_mode_shortcut(&format!(" <{}> {}", letter_shortcut, full_text), palette)
}
CtrlKeyMode::Unselected => unselected_mode_shortcut(
letter_shortcut,
&format!(" {}", full_text),
palette,
separator,
),
CtrlKeyMode::Selected => selected_mode_shortcut(
letter_shortcut,
&format!(" {}", full_text),
palette,
separator,
),
CtrlKeyMode::Disabled => disabled_mode_shortcut(
&format!(" <{}> {}", letter_shortcut, full_text),
palette,
separator,
),
}
}
fn shortened_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart {
fn shortened_ctrl_key(
key: &CtrlKeyShortcut,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let shortened_text = key.shortened_text();
let letter_shortcut = key.letter_shortcut();
let shortened_text = match key.action {
@ -176,33 +206,47 @@ fn shortened_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePa
};
match key.mode {
CtrlKeyMode::Unselected => {
unselected_mode_shortcut(letter_shortcut, &shortened_text, palette)
unselected_mode_shortcut(letter_shortcut, &shortened_text, palette, separator)
}
CtrlKeyMode::Selected => {
selected_mode_shortcut(letter_shortcut, &shortened_text, palette, separator)
}
CtrlKeyMode::Selected => selected_mode_shortcut(letter_shortcut, &shortened_text, palette),
CtrlKeyMode::Disabled => disabled_mode_shortcut(
&format!(" <{}>{}", letter_shortcut, shortened_text),
palette,
),
CtrlKeyMode::Disabled => disabled_mode_shortcut(
&format!(" <{}>{}", letter_shortcut, shortened_text),
palette,
separator,
),
}
}
fn single_letter_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart {
fn single_letter_ctrl_key(
key: &CtrlKeyShortcut,
palette: ColoredElements,
separator: &str,
) -> LinePart {
let letter_shortcut = key.letter_shortcut();
match key.mode {
CtrlKeyMode::Unselected => unselected_mode_shortcut_single_letter(letter_shortcut, palette),
CtrlKeyMode::Selected => selected_mode_shortcut_single_letter(letter_shortcut, palette),
CtrlKeyMode::Disabled => disabled_mode_shortcut(&format!(" {}", letter_shortcut), palette),
CtrlKeyMode::Unselected => {
unselected_mode_shortcut_single_letter(letter_shortcut, palette, separator)
}
CtrlKeyMode::Selected => {
selected_mode_shortcut_single_letter(letter_shortcut, palette, separator)
}
CtrlKeyMode::Disabled => {
disabled_mode_shortcut(&format!(" {}", letter_shortcut), palette, separator)
}
}
}
fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElements) -> LinePart {
fn key_indicators(
max_len: usize,
keys: &[CtrlKeyShortcut],
palette: ColoredElements,
separator: &str,
) -> LinePart {
let mut line_part = LinePart::default();
for ctrl_key in keys {
let key = full_ctrl_key(ctrl_key, palette);
let key = full_ctrl_key(ctrl_key, palette, separator);
line_part.part = format!("{}{}", line_part.part, key.part);
line_part.len += key.len;
}
@ -211,7 +255,7 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem
}
line_part = LinePart::default();
for ctrl_key in keys {
let key = shortened_ctrl_key(ctrl_key, palette);
let key = shortened_ctrl_key(ctrl_key, palette, separator);
line_part.part = format!("{}{}", line_part.part, key.part);
line_part.len += key.len;
}
@ -220,7 +264,7 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem
}
line_part = LinePart::default();
for ctrl_key in keys {
let key = single_letter_ctrl_key(ctrl_key, palette);
let key = single_letter_ctrl_key(ctrl_key, palette, separator);
line_part.part = format!("{}{}", line_part.part, key.part);
line_part.len += key.len;
}
@ -231,17 +275,17 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem
line_part
}
pub fn superkey(palette: ColoredElements) -> LinePart {
pub fn superkey(palette: ColoredElements, separator: &str) -> LinePart {
let prefix_text = " Ctrl +";
let prefix = palette.superkey_prefix.paint(prefix_text);
let suffix_separator = palette.superkey_suffix_separator.paint(ARROW_SEPARATOR);
let suffix_separator = palette.superkey_suffix_separator.paint(separator);
LinePart {
part: ANSIStrings(&[prefix, suffix_separator]).to_string(),
len: prefix_text.chars().count(),
}
}
pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
let colored_elements = color_elements(help.palette);
match &help.mode {
InputMode::Locked => key_indicators(
@ -255,6 +299,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
InputMode::Resize => key_indicators(
max_len,
@ -267,6 +312,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
InputMode::Pane => key_indicators(
max_len,
@ -279,6 +325,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
InputMode::Tab | InputMode::RenameTab => key_indicators(
max_len,
@ -291,6 +338,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
InputMode::Scroll => key_indicators(
max_len,
@ -303,6 +351,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
InputMode::Normal => key_indicators(
max_len,
@ -315,6 +364,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart {
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
}
}

View File

@ -140,9 +140,15 @@ impl ZellijPlugin for State {
}
fn render(&mut self, _rows: usize, cols: usize) {
let separator = if !self.mode_info.capabilities.arrow_fonts {
ARROW_SEPARATOR
} else {
&""
};
let colored_elements = color_elements(self.mode_info.palette);
let superkey = superkey(colored_elements);
let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len);
let superkey = superkey(colored_elements, separator);
let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len, separator);
let first_line = format!("{}{}", superkey, ctrl_keys);
let second_line = keybinds(&self.mode_info, cols);

View File

@ -48,7 +48,7 @@ fn populate_tabs_in_tab_line(
}
}
fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart {
fn left_more_message(tab_count_to_the_left: usize, palette: Palette, separator: &str) -> LinePart {
if tab_count_to_the_left == 0 {
return LinePart {
part: String::new(),
@ -62,11 +62,11 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart
};
// 238
let more_text_len = more_text.chars().count() + 2; // 2 for the arrows
let left_separator = style!(palette.bg, palette.orange).paint(ARROW_SEPARATOR);
let left_separator = style!(palette.bg, palette.orange).paint(separator);
let more_styled_text = style!(palette.black, palette.orange)
.bold()
.paint(more_text);
let right_separator = style!(palette.orange, palette.bg).paint(ARROW_SEPARATOR);
let right_separator = style!(palette.orange, palette.bg).paint(separator);
let more_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, more_styled_text, right_separator,])
@ -77,7 +77,11 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart
}
}
fn right_more_message(tab_count_to_the_right: usize, palette: Palette) -> LinePart {
fn right_more_message(
tab_count_to_the_right: usize,
palette: Palette,
separator: &str,
) -> LinePart {
if tab_count_to_the_right == 0 {
return LinePart {
part: String::new(),
@ -90,11 +94,11 @@ fn right_more_message(tab_count_to_the_right: usize, palette: Palette) -> LinePa
" +many → ".to_string()
};
let more_text_len = more_text.chars().count() + 1; // 2 for the arrow
let left_separator = style!(palette.bg, palette.orange).paint(ARROW_SEPARATOR);
let left_separator = style!(palette.bg, palette.orange).paint(separator);
let more_styled_text = style!(palette.black, palette.orange)
.bold()
.paint(more_text);
let right_separator = style!(palette.orange, palette.bg).paint(ARROW_SEPARATOR);
let right_separator = style!(palette.orange, palette.bg).paint(separator);
let more_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, more_styled_text, right_separator,])
@ -111,14 +115,15 @@ fn add_previous_tabs_msg(
title_bar: &mut Vec<LinePart>,
cols: usize,
palette: Palette,
separator: &str,
) {
while get_current_title_len(&tabs_to_render)
+ left_more_message(tabs_before_active.len(), palette).len
+ left_more_message(tabs_before_active.len(), palette, separator).len
>= cols
{
tabs_before_active.push(tabs_to_render.remove(0));
}
let left_more_message = left_more_message(tabs_before_active.len(), palette);
let left_more_message = left_more_message(tabs_before_active.len(), palette, separator);
title_bar.push(left_more_message);
}
@ -127,14 +132,15 @@ fn add_next_tabs_msg(
title_bar: &mut Vec<LinePart>,
cols: usize,
palette: Palette,
separator: &str,
) {
while get_current_title_len(&title_bar)
+ right_more_message(tabs_after_active.len(), palette).len
+ right_more_message(tabs_after_active.len(), palette, separator).len
>= cols
{
tabs_after_active.insert(0, title_bar.pop().unwrap());
}
let right_more_message = right_more_message(tabs_after_active.len(), palette);
let right_more_message = right_more_message(tabs_after_active.len(), palette, separator);
title_bar.push(right_more_message);
}
@ -148,11 +154,20 @@ fn tab_line_prefix(palette: Palette) -> LinePart {
}
}
pub fn tab_separator(capabilities: PluginCapabilities) -> &'static str {
if !capabilities.arrow_fonts {
ARROW_SEPARATOR
} else {
&""
}
}
pub fn tab_line(
mut all_tabs: Vec<LinePart>,
active_tab_index: usize,
cols: usize,
palette: Palette,
capabilities: PluginCapabilities,
) -> Vec<LinePart> {
let mut tabs_to_render: Vec<LinePart> = vec![];
let mut tabs_after_active = all_tabs.split_off(active_tab_index);
@ -180,6 +195,7 @@ pub fn tab_line(
&mut tab_line,
cols - prefix.len,
palette,
tab_separator(capabilities),
);
}
tab_line.append(&mut tabs_to_render);
@ -189,6 +205,7 @@ pub fn tab_line(
&mut tab_line,
cols - prefix.len,
palette,
tab_separator(capabilities),
);
}
tab_line.insert(0, prefix);

View File

@ -60,10 +60,17 @@ impl ZellijPlugin for State {
t.position,
t.is_sync_panes_active,
self.mode_info.palette,
self.mode_info.capabilities,
);
all_tabs.push(tab);
}
let tab_line = tab_line(all_tabs, active_tab_index, cols, self.mode_info.palette);
let tab_line = tab_line(
all_tabs,
active_tab_index,
cols,
self.mode_info.palette,
self.mode_info.capabilities,
);
let mut s = String::new();
for bar_part in tab_line {
s = format!("{}{}", s, bar_part.part);

View File

@ -1,15 +1,15 @@
use crate::{LinePart, ARROW_SEPARATOR};
use crate::{line::tab_separator, LinePart};
use ansi_term::ANSIStrings;
use zellij_tile::prelude::*;
use zellij_tile_utils::style;
pub fn active_tab(text: String, palette: Palette) -> LinePart {
let left_separator = style!(palette.bg, palette.green).paint(ARROW_SEPARATOR);
pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart {
let left_separator = style!(palette.bg, palette.green).paint(separator);
let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the text padding
let tab_styled_text = style!(palette.black, palette.green)
.bold()
.paint(format!(" {} ", text));
let right_separator = style!(palette.green, palette.bg).paint(ARROW_SEPARATOR);
let right_separator = style!(palette.green, palette.bg).paint(separator);
let tab_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, tab_styled_text, right_separator,])
@ -20,13 +20,13 @@ pub fn active_tab(text: String, palette: Palette) -> LinePart {
}
}
pub fn non_active_tab(text: String, palette: Palette) -> LinePart {
let left_separator = style!(palette.bg, palette.fg).paint(ARROW_SEPARATOR);
pub fn non_active_tab(text: String, palette: Palette, separator: &str) -> LinePart {
let left_separator = style!(palette.bg, palette.fg).paint(separator);
let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the padding
let tab_styled_text = style!(palette.black, palette.fg)
.bold()
.paint(format!(" {} ", text));
let right_separator = style!(palette.fg, palette.bg).paint(ARROW_SEPARATOR);
let right_separator = style!(palette.fg, palette.bg).paint(separator);
let tab_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, tab_styled_text, right_separator,])
@ -43,7 +43,9 @@ pub fn tab_style(
position: usize,
is_sync_panes_active: bool,
palette: Palette,
capabilities: PluginCapabilities,
) -> LinePart {
let separator = tab_separator(capabilities);
let mut tab_text = if text.is_empty() {
format!("Tab #{}", position + 1)
} else {
@ -53,8 +55,8 @@ pub fn tab_style(
tab_text.push_str(" (Sync)");
}
if is_active_tab {
active_tab(tab_text, palette)
active_tab(tab_text, palette, separator)
} else {
non_active_tab(tab_text, palette)
non_active_tab(tab_text, palette, separator)
}
}

View File

@ -1,6 +1,7 @@
---
keybinds:
normal:
- unbind : true
- action: [GoToTab: 1,]
key: [F: 1,]
- action: [GoToTab: 2,]

View File

@ -1,4 +1,5 @@
---
simplified_ui: true
keybinds:
unbind: true
normal:

View File

@ -1,4 +1,5 @@
use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV};
use crate::common::input::options::Options;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use structopt::StructOpt;
@ -10,6 +11,10 @@ pub struct CliArgs {
#[structopt(long)]
pub max_panes: Option<usize>,
/// Speficy, if a simplified layout should be used that is compatible with more fonts
#[structopt(long)]
pub simplified: bool,
/// Change where zellij looks for layouts and plugins
#[structopt(long)]
pub data_dir: Option<PathBuf>,
@ -36,21 +41,20 @@ pub struct CliArgs {
#[derive(Debug, StructOpt, Clone, Serialize, Deserialize)]
pub enum ConfigCli {
/// Change the behaviour of zellij
#[structopt(name = "option")]
Config {
/// Disables loading of configuration file at default location
#[structopt(long)]
clean: bool,
},
#[structopt(name = "options")]
Options(Options),
#[structopt(name = "generate-completion")]
GenerateCompletion { shell: String },
#[structopt(name = "setup")]
Setup {
/// Disables loading of configuration file at default location
/// Dump the default configuration file to stdout
#[structopt(long)]
dump_config: bool,
/// Disables loading of configuration file at default location,
/// loads the defaults that zellij ships with
#[structopt(long)]
clean: bool,
},
}

View File

@ -42,7 +42,11 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
os_input.connect_to_server();
os_input.send_to_server(ServerInstruction::NewClient(full_screen_ws, opts));
os_input.send_to_server(ServerInstruction::NewClient(
full_screen_ws,
opts,
config.options.clone(),
));
os_input.set_raw_mode(0);
let (send_client_instructions, receive_client_instructions): SyncChannelWithContext<

View File

@ -6,10 +6,11 @@ use std::io::{self, Read};
use std::path::{Path, PathBuf};
use super::keybinds::{Keybinds, KeybindsFromYaml};
use super::options::Options;
use crate::cli::{CliArgs, ConfigCli};
use crate::common::setup;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
const DEFAULT_CONFIG_FILE_NAME: &str = "config.yaml";
@ -19,13 +20,16 @@ type ConfigResult = Result<Config, ConfigError>;
/// Intermediate deserialization config struct
#[derive(Debug, Deserialize)]
pub struct ConfigFromYaml {
#[serde(flatten)]
pub options: Option<Options>,
pub keybinds: Option<KeybindsFromYaml>,
}
/// Main configuration.
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Config {
pub keybinds: Keybinds,
pub options: Options,
}
#[derive(Debug)]
@ -43,7 +47,8 @@ pub enum ConfigError {
impl Default for Config {
fn default() -> Self {
let keybinds = Keybinds::default();
Config { keybinds }
let options = Options::default();
Config { keybinds, options }
}
}
@ -55,7 +60,7 @@ impl TryFrom<&CliArgs> for Config {
return Config::new(&path);
}
if let Some(ConfigCli::Config { clean, .. }) = opts.option {
if let Some(ConfigCli::Setup { clean, .. }) = opts.option {
if clean {
return Config::from_default_assets();
}
@ -84,7 +89,8 @@ impl Config {
pub fn from_yaml(yaml_config: &str) -> ConfigResult {
let config_from_yaml: ConfigFromYaml = serde_yaml::from_str(&yaml_config)?;
let keybinds = Keybinds::get_default_keybinds_with_config(config_from_yaml.keybinds);
Ok(Config { keybinds })
let options = Options::from_yaml(config_from_yaml.options);
Ok(Config { keybinds, options })
}
/// Deserializes from given path.
@ -172,7 +178,10 @@ mod config_test {
#[test]
fn try_from_cli_args_with_option_clean() {
let mut opts = CliArgs::default();
opts.option = Some(ConfigCli::Config { clean: true });
opts.option = Some(ConfigCli::Setup {
clean: true,
dump_config: false,
});
let result = Config::try_from(&opts);
assert!(result.is_ok());
}

View File

@ -11,7 +11,7 @@ use crate::server::ServerInstruction;
use crate::CommandIsExecuting;
use termion::input::{TermRead, TermReadEventsAndRaw};
use zellij_tile::data::{InputMode, Key, ModeInfo, Palette};
use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities};
/// Handles the dispatching of [`Action`]s according to the current
/// [`InputMode`], and keep tracks of the current [`InputMode`].
@ -149,6 +149,7 @@ impl InputHandler {
// TODO this should probably be automatically generated in some way
pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo {
let mut keybinds: Vec<(String, String)> = vec![];
let capabilities = PluginCapabilities { arrow_fonts: true };
match mode {
InputMode::Normal | InputMode::Locked => {}
InputMode::Resize => {
@ -182,6 +183,7 @@ pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo {
mode,
keybinds,
palette,
capabilities,
}
}

View File

@ -4,14 +4,14 @@ use std::collections::HashMap;
use super::actions::Action;
use super::config;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use strum::IntoEnumIterator;
use zellij_tile::data::*;
/// Used in the config struct
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct Keybinds(HashMap<InputMode, ModeKeybinds>);
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct ModeKeybinds(HashMap<Key, Vec<Action>>);
/// Intermediate struct used for deserialisation

View File

@ -4,3 +4,4 @@ pub mod actions;
pub mod config;
pub mod handler;
pub mod keybinds;
pub mod options;

View File

@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
use structopt::StructOpt;
#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, StructOpt)]
/// Options that can be set either through the config file,
/// or cli flags
pub struct Options {
/// Allow plugins to use a more compatible font type
#[structopt(long)]
pub simplified_ui: bool,
}
impl Options {
pub fn from_yaml(from_yaml: Option<Options>) -> Options {
if let Some(opts) = from_yaml {
opts
} else {
Options::default()
}
}
}

View File

@ -4,6 +4,8 @@ use std::collections::BTreeMap;
use std::os::unix::io::RawFd;
use std::str;
use crate::cli::ConfigCli;
use crate::common::input::options::Options;
use crate::common::pty::{PtyInstruction, VteBytes};
use crate::common::thread_bus::Bus;
use crate::errors::{ContextType, ScreenContext};
@ -14,7 +16,7 @@ use crate::server::ServerInstruction;
use crate::tab::Tab;
use crate::wasm_vm::PluginInstruction;
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, TabInfo};
use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo};
/// Instructions that can be sent to the [`Screen`].
#[derive(Debug, Clone)]
@ -328,14 +330,24 @@ pub fn screen_thread_main(
bus: Bus<ScreenInstruction>,
max_panes: Option<usize>,
full_screen_ws: PositionAndSize,
options: Option<ConfigCli>,
config_options: Options,
) {
let colors = bus.os_input.as_ref().unwrap().load_palette();
let capabilities = if let Some(ConfigCli::Options(options)) = options {
options.simplified_ui
} else {
config_options.simplified_ui
};
let mut screen = Screen::new(
bus,
&full_screen_ws,
max_panes,
ModeInfo {
palette: colors,
capabilities: PluginCapabilities {
arrow_fonts: capabilities,
},
..ModeInfo::default()
},
InputMode::Normal,

View File

@ -12,7 +12,7 @@ use crate::client::ClientInstruction;
use crate::common::thread_bus::{Bus, ThreadSenders};
use crate::common::{
errors::{ContextType, ServerContext},
input::actions::Action,
input::{actions::Action, options::Options},
os_input_output::{set_permissions, ServerOsApi},
pty::{pty_thread_main, Pty, PtyInstruction},
screen::{screen_thread_main, ScreenInstruction},
@ -30,7 +30,7 @@ use route::route_thread_main;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ServerInstruction {
TerminalResize(PositionAndSize),
NewClient(PositionAndSize, CliArgs),
NewClient(PositionAndSize, CliArgs, Options),
Action(Action),
Render(Option<String>),
UnblockInputThread,
@ -115,9 +115,14 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> {
let (instruction, mut err_ctx) = server_receiver.recv().unwrap();
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction)));
match instruction {
ServerInstruction::NewClient(full_screen_ws, opts) => {
let session_data =
init_session(os_input.clone(), opts, to_server.clone(), full_screen_ws);
ServerInstruction::NewClient(full_screen_ws, opts, config_options) => {
let session_data = init_session(
os_input.clone(),
opts,
config_options,
to_server.clone(),
full_screen_ws,
);
*sessions.write().unwrap() = Some(session_data);
sessions
.read()
@ -150,6 +155,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> {
fn init_session(
os_input: Box<dyn ServerOsApi>,
opts: CliArgs,
config_options: Options,
to_server: SenderWithContext<ServerInstruction>,
full_screen_ws: PositionAndSize,
) -> SessionMetaData {
@ -208,9 +214,16 @@ fn init_session(
Some(os_input.clone()),
);
let max_panes = opts.max_panes;
let options = opts.option;
move || {
screen_thread_main(screen_bus, max_panes, full_screen_ws);
screen_thread_main(
screen_bus,
max_panes,
full_screen_ws,
options,
config_options,
);
}
})
.unwrap();

View File

@ -125,6 +125,7 @@ pub struct ModeInfo {
// FIXME: This should probably return Keys and Actions, then sort out strings plugin-side
pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description>
pub palette: Palette,
pub capabilities: PluginCapabilities,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
@ -141,3 +142,8 @@ pub struct PluginIds {
pub plugin_id: u32,
pub zellij_pid: u32,
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct PluginCapabilities {
pub arrow_fonts: bool,
}