* work * moar work * notes * work * separate to terminal and control channels * stdin working * serve html web client initial * serve static assets loaded with include_dir * merge * enable_web_server config parameter * compile time flag to disable web server capability * rustfmt * add license to all xterm.js assets * mouse working except copy/paste * helpful comment * web client improvements - move script to js file - add favicon - add nerd font - change title TODO: investigate if font license embedded in otf is sufficient * get mouse to work properly * kitty keyboard support initial * fix wrong type in preload link * wip axum websocket handlers - upgrade axum to v0.8.1, enable ws feature - begin setup of websocket handlers - tidy up imports * replace control listener * handle terminal websocket with axum * cleanup Cargo.toml * kitty fixes and bracketed paste * fix(mouse): pane not found crash * initial session switching infra * add `web_client_font` option * session switching, creation and resurrection working through the session manager * move session module to zellij-utils and share logic with web-client * some cleanups * require restart for enable-web-server * use session name from router * write config to disk and watch for config changes * rename session name to ipc path * add basic panic handler, make render_to_client exit on channel close * use while let instead of loop * handle websocket close * add mouse motions * make clipboard work * add weblink handling and webgl rendering * add todo * fix: use session name instead of patch on session switch * use "default" layout for new sessions * ui indication for session being shared * share this session ui * plugin assets * Fix process crash on mac with notify watcher. Use poll watcher instead of recommended as a workaround. * make url session switching and creation work * start welcome screen on root url * scaffold control messages, set font from config * set dimensions on session start * bring back session name from url * send bytes on terminal websocket instead of json - create web client os input and id before websocket connection * draft ui * work * refactor ui * remove otf font, remove margins to avoid scrollbar * version query endpoint for server status * web session info query endpoint * refactor: move stuff around * add web client info to session metadata * make tests pass * populate real data in session list * remove unnecessary endpoint * add web_client node to config, add font option * remove web_client_font * allow disabling the web session through the config - WIP * formalize sharing/not-sharing configuration * fix tests * allow shutting down web server * display error when web clients are forbidden to attach * only show sessions that allow web clients if this is a web client * style(fmt): rustfmt * fix: query web server from Zellij rather than from each plugin * remove log spam * handle some error paths better in the web client * allow controlling the web server through the cli * allow configuring the web server's ip/port * fix tests and format code * use direct WebServerStatus event instead of piggy-backing on SessionInfo * plugin revamp initial * make plugin responsive * adjust plugin title * refactor: share plugin * refactor: share plugin * add cors middleware * some fixes for running without a compiled web server capability * display error when starting the share plugin without web server support * clarify config * add pipelines to compile zellij without web support * display error when unable to start web server * only query web server when share plugin is running * refactor(web-client): connection table * give zellij_server_listener access to the control channel * fixes and clarifications * refactor: consolidate generate_unique_session_name * give proper error when trying to attach to a forbidden session * change browser URL when switching sessions * add keyboard shortcut * enforce https when bound to non-loopback ip * initial authentication token implementation * background color from theme * initial web client theme config * basic token generation ui * refactor set config message creation * also set body background * allow editing scrollback for plugins too * set scrollback to 0 * properly parse colors in config * generate token from plugin * nice login modals * initial token management screen * implement token authentication * refactor(share): token management screen * style(fmt): rustfmt * fix(plugin): some minor bugs * refactor(share): main screen * refactor(share): token screen * refactor(share): main * refactor(share): ui components * fix(responsiveness): properly send usage_width to the render function * fix cli commands and add some verbosity * add support for settings ansi and selection colors * add cursor and cursor accent * basic web client tests * fix tests * refactor: web client * use session tokens for authentication * improve modals * move shutdown to ipc * refactor: ipc logic * serialize theme config for web client * update tests * refactor: move some stuff around to prepare for config hot reload * config live reloading for the web clients * change remember-me UI wording * improve xterm.js link handling * make sure terminal is focused on mousemove * remove deprecated sharing indication from compact-bar * gate deps and functionality behind the web_server_compatibility feature * feat(build): add --no-web flag in all the places * fix some other build flows * add new assets * update CI for no-web (untested) * make more dependencies optional * update axum-extra * add web client configuration options * gracefully close connections on server exit * tests for graceful connection closing * handle client-side reconnect when server is down * fix: make sure ipc bus folder exists before starting * add commands to manage login tokens from the cli * style(fmt): rustfmt * some cleanups * fix(ux): allow alt-right-click on the web client without opening the context menu * fix: prevent attaching to welcome screen * fix: reload config issues * fix long socket path on macos * normalize config conversion and fix color gap in browser * revoke session_token cookie if it is not valid * fix: visual bug with multiple clients in extremely small screen sizes * fix: only include rusqlite for the web server capability builds * update e2e snapshots * refactor(web): client side js * some cleanups * moar cleanups * fix(tests): wait for server instead of using a fixed timeout * debug CI * fix(tests): use spawn_blocking for running the test web server * fix(tests): wait for http rather than tcp port * fix(tests): properly pass config path - hopefully this is the issue... * success! bring back the rest of the tests * attempt to fix the macos CI issue * docs(changelog): add PR --------- Co-authored-by: Thomas Linford <linford.t@gmail.com>
149 lines
5.7 KiB
Rust
149 lines
5.7 KiB
Rust
pub mod actions;
|
|
pub mod command;
|
|
pub mod config;
|
|
pub mod keybinds;
|
|
pub mod layout;
|
|
pub mod mouse;
|
|
pub mod options;
|
|
pub mod permission;
|
|
pub mod plugins;
|
|
pub mod theme;
|
|
pub mod web_client;
|
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
pub use not_wasm::*;
|
|
|
|
#[cfg(not(target_family = "wasm"))]
|
|
mod not_wasm {
|
|
use crate::{
|
|
data::{BareKey, InputMode, KeyModifier, KeyWithModifier, ModeInfo, PluginCapabilities},
|
|
envs,
|
|
ipc::ClientAttributes,
|
|
};
|
|
use termwiz::input::{InputEvent, InputParser, KeyCode, KeyEvent, Modifiers};
|
|
|
|
use super::keybinds::Keybinds;
|
|
use std::collections::BTreeSet;
|
|
|
|
/// Creates a [`ModeInfo`] struct indicating the current [`InputMode`] and its keybinds
|
|
/// (as pairs of [`String`]s).
|
|
pub fn get_mode_info(
|
|
mode: InputMode,
|
|
attributes: &ClientAttributes,
|
|
capabilities: PluginCapabilities,
|
|
keybinds: &Keybinds,
|
|
base_mode: Option<InputMode>,
|
|
) -> ModeInfo {
|
|
let keybinds = keybinds.to_keybinds_vec();
|
|
let session_name = envs::get_session_name().ok();
|
|
|
|
ModeInfo {
|
|
mode,
|
|
base_mode,
|
|
keybinds,
|
|
style: attributes.style,
|
|
capabilities,
|
|
session_name,
|
|
editor: None,
|
|
shell: None,
|
|
web_clients_allowed: None,
|
|
web_sharing: None,
|
|
currently_marking_pane_group: None,
|
|
is_web_client: None,
|
|
web_server_ip: None,
|
|
web_server_port: None,
|
|
web_server_capability: None,
|
|
}
|
|
}
|
|
|
|
// used for parsing keys to plugins
|
|
pub fn parse_keys(input_bytes: &[u8]) -> Vec<KeyWithModifier> {
|
|
let mut ret = vec![];
|
|
let mut input_parser = InputParser::new(); // this is the termwiz InputParser
|
|
let maybe_more = false;
|
|
let parse_input_event = |input_event: InputEvent| {
|
|
if let InputEvent::Key(key_event) = input_event {
|
|
ret.push(cast_termwiz_key(key_event, input_bytes, None));
|
|
}
|
|
};
|
|
input_parser.parse(input_bytes, parse_input_event, maybe_more);
|
|
ret
|
|
}
|
|
|
|
fn key_is_bound(key: &KeyWithModifier, keybinds: &Keybinds, mode: &InputMode) -> bool {
|
|
keybinds
|
|
.get_actions_for_key_in_mode(mode, key)
|
|
.map_or(false, |actions| !actions.is_empty())
|
|
}
|
|
|
|
// FIXME: This is an absolutely cursed function that should be destroyed as soon
|
|
// as an alternative that doesn't touch zellij-tile can be developed...
|
|
pub fn cast_termwiz_key(
|
|
event: KeyEvent,
|
|
raw_bytes: &[u8],
|
|
keybinds_mode: Option<(&Keybinds, &InputMode)>,
|
|
) -> KeyWithModifier {
|
|
let termwiz_modifiers = event.modifiers;
|
|
|
|
// *** THIS IS WHERE WE SHOULD WORK AROUND ISSUES WITH TERMWIZ ***
|
|
if raw_bytes == [8] {
|
|
return KeyWithModifier::new(BareKey::Char('h')).with_ctrl_modifier();
|
|
};
|
|
|
|
if raw_bytes == [10] {
|
|
if let Some((keybinds, mode)) = keybinds_mode {
|
|
let ctrl_j = KeyWithModifier::new(BareKey::Char('j')).with_ctrl_modifier();
|
|
if key_is_bound(&ctrl_j, keybinds, mode) {
|
|
return ctrl_j;
|
|
}
|
|
}
|
|
}
|
|
let mut modifiers = BTreeSet::new();
|
|
if termwiz_modifiers.contains(Modifiers::CTRL) {
|
|
modifiers.insert(KeyModifier::Ctrl);
|
|
}
|
|
if termwiz_modifiers.contains(Modifiers::ALT) {
|
|
modifiers.insert(KeyModifier::Alt);
|
|
}
|
|
if termwiz_modifiers.contains(Modifiers::SHIFT) {
|
|
modifiers.insert(KeyModifier::Shift);
|
|
}
|
|
|
|
match event.key {
|
|
KeyCode::Char(c) => {
|
|
if c == '\0' {
|
|
// NUL character, probably ctrl-space
|
|
KeyWithModifier::new(BareKey::Char(' ')).with_ctrl_modifier()
|
|
} else {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char(c), modifiers)
|
|
}
|
|
},
|
|
KeyCode::Backspace => {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Backspace, modifiers)
|
|
},
|
|
KeyCode::LeftArrow | KeyCode::ApplicationLeftArrow => {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Left, modifiers)
|
|
},
|
|
KeyCode::RightArrow | KeyCode::ApplicationRightArrow => {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Right, modifiers)
|
|
},
|
|
KeyCode::UpArrow | KeyCode::ApplicationUpArrow => {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Up, modifiers)
|
|
},
|
|
KeyCode::DownArrow | KeyCode::ApplicationDownArrow => {
|
|
KeyWithModifier::new_with_modifiers(BareKey::Down, modifiers)
|
|
},
|
|
KeyCode::Home => KeyWithModifier::new_with_modifiers(BareKey::Home, modifiers),
|
|
KeyCode::End => KeyWithModifier::new_with_modifiers(BareKey::End, modifiers),
|
|
KeyCode::PageUp => KeyWithModifier::new_with_modifiers(BareKey::PageUp, modifiers),
|
|
KeyCode::PageDown => KeyWithModifier::new_with_modifiers(BareKey::PageDown, modifiers),
|
|
KeyCode::Tab => KeyWithModifier::new_with_modifiers(BareKey::Tab, modifiers),
|
|
KeyCode::Delete => KeyWithModifier::new_with_modifiers(BareKey::Delete, modifiers),
|
|
KeyCode::Insert => KeyWithModifier::new_with_modifiers(BareKey::Insert, modifiers),
|
|
KeyCode::Function(n) => KeyWithModifier::new_with_modifiers(BareKey::F(n), modifiers),
|
|
KeyCode::Escape => KeyWithModifier::new_with_modifiers(BareKey::Esc, modifiers),
|
|
KeyCode::Enter => KeyWithModifier::new_with_modifiers(BareKey::Enter, modifiers),
|
|
_ => KeyWithModifier::new(BareKey::Esc),
|
|
}
|
|
}
|
|
}
|