Skip to content
Draft
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
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ keywords = ["terminal", "egui"]
[workspace.dependencies]
alacritty_terminal = { git = "https://github.com/alacritty/alacritty" }
anyhow = "1"
bytesize = "1"
camino = "1"
catppuccin-egui = { git = "https://github.com/iamazy/catppuccin-egui", branch = "egui30" }
chrono = "0.4"
copypasta = "0.10"
Expand All @@ -34,6 +36,7 @@ egui_form = "0.5"
egui-phosphor = "0.9"
egui-theme-switch = "0.2.3"
egui-toast = "0.16"
file-format = "0.26"
garde = "0.22"
homedir = "0.3"
indexmap = "2"
Expand All @@ -48,10 +51,9 @@ serde = "1"
signal-hook = "0.3"
smol = "2"
thiserror = "2"
time = "0.3"
tracing = "0.1"
tracing-subscriber = "0.3"
uuid = "1"
validator = "0.20"
wezterm-ssh = { git = "https://github.com/iamazy/wezterm.git", branch = "nxssh" }
windows = "0.59"

Expand Down
6 changes: 6 additions & 0 deletions crates/egui-term/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@ keywords.workspace = true
[dependencies]
alacritty_terminal.workspace = true
anyhow.workspace = true
bytesize.workspace = true
camino.workspace = true
copypasta.workspace = true
egui.workspace = true
egui_extras.workspace = true
file-format.workspace = true
homedir.workspace = true
open.workspace = true
parking_lot.workspace = true
polling.workspace = true
smol.workspace = true
thiserror.workspace = true
time.workspace = true
tracing.workspace = true
wezterm-ssh = { workspace = true, features = ["vendored-openssl"] }

Expand Down
9 changes: 4 additions & 5 deletions crates/egui-term/examples/custom_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use copypasta::ClipboardContext;
use egui::{Id, Key, Modifiers, Vec2};
use egui::{Key, Modifiers, Vec2};
use egui_term::{
generate_bindings, Binding, BindingAction, InputKind, KeyboardBinding, PtyEvent, TermMode,
Terminal, TerminalContext, TerminalFont, TerminalOptions, TerminalTheme, TerminalView,
Expand All @@ -11,7 +11,6 @@ pub struct App {
terminal_font: TerminalFont,
terminal_theme: TerminalTheme,
multi_exec: bool,
active_id: Option<Id>,
clipboard: ClipboardContext,
pty_proxy_receiver: Receiver<(u64, PtyEvent)>,
custom_terminal_bindings: Vec<(Binding<InputKind>, BindingAction)>,
Expand Down Expand Up @@ -67,7 +66,6 @@ impl App {
terminal_theme: TerminalTheme::default(),
terminal_font: TerminalFont::default(),
multi_exec: false,
active_id: None,
clipboard: ClipboardContext::new().unwrap(),
pty_proxy_receiver,
custom_terminal_bindings,
Expand All @@ -83,13 +81,14 @@ impl eframe::App for App {
}

egui::CentralPanel::default().show(ctx, |ui| {
let term_ctx = TerminalContext::new(&mut self.terminal_backend, &mut self.clipboard);
let term_ctx =
TerminalContext::new(&mut self.terminal_backend, &mut self.clipboard, &mut false);
let term_opt = TerminalOptions {
font: &mut self.terminal_font,
multi_exec: &mut self.multi_exec,
theme: &mut self.terminal_theme,
default_font_size: 14.,
active_tab_id: &mut self.active_id,
active_tab_id: None,
};
let terminal = TerminalView::new(ui, term_ctx, term_opt)
.set_focus(true)
Expand Down
59 changes: 59 additions & 0 deletions crates/egui-term/examples/sftp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::io::Read;

use egui_term::TermError;
use tracing::{error, trace};
use wezterm_ssh::{Config, Session, SessionEvent};

fn main() -> Result<(), TermError> {
let mut config = Config::new();
config.add_default_config_files();
let config = config.for_host("127.0.0.1");
smol::block_on(async move {
let (session, events) = Session::connect(config)?;

while let Ok(event) = events.recv().await {
match event {
SessionEvent::Banner(banner) => {
if let Some(banner) = banner {
trace!("{}", banner);
}
}
SessionEvent::HostVerify(verify) => {
verify.answer(true).await?;
}
SessionEvent::Authenticate(auth) => {
// login with ssh config, so no answers needed
auth.answer(vec![]).await?;
}
SessionEvent::HostVerificationFailed(failed) => {
error!("host verification failed: {failed}");
return Err(TermError::HostVerification(failed));
}
SessionEvent::Error(err) => {
error!("ssh login error: {err}");
return Err(TermError::Box(err.into()));
}
SessionEvent::Authenticated => break,
}
}

let mut exec_ret = session.exec("pwd", None).await.unwrap();

let mut s = String::new();
exec_ret.stdout.read_to_string(&mut s).unwrap();

let sftp = session.sftp();
match sftp.read_dir(s.trim()).await {
Ok(entries) => {
for (path, _meta) in entries {
println!("path: {}", path.as_path())
}
}
Err(err) => println!("{err}"),
}

Ok(())
})?;

Ok(())
}
8 changes: 3 additions & 5 deletions crates/egui-term/examples/tabs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use copypasta::ClipboardContext;
use eframe::glow;
use egui::Id;
use egui_term::{
PtyEvent, Terminal, TerminalContext, TerminalFont, TerminalOptions, TerminalTheme, TerminalView,
};
Expand All @@ -14,7 +13,6 @@ pub struct App {
command_receiver: Receiver<(u64, PtyEvent)>,
tab_manager: TabManager,
multi_exec: bool,
active_tab: Option<Id>,
clipboard: ClipboardContext,
}

Expand All @@ -26,7 +24,6 @@ impl App {
command_receiver,
tab_manager: TabManager::new(),
multi_exec: false,
active_tab: None,
clipboard: ClipboardContext::new().unwrap(),
}
}
Expand Down Expand Up @@ -73,13 +70,14 @@ impl eframe::App for App {

egui::CentralPanel::default().show(ctx, |ui| {
if let Some(tab) = self.tab_manager.get_active() {
let term_ctx = TerminalContext::new(&mut tab.backend, &mut self.clipboard);
let term_ctx =
TerminalContext::new(&mut tab.backend, &mut self.clipboard, &mut false);
let term_opt = TerminalOptions {
font: &mut tab.font,
multi_exec: &mut self.multi_exec,
theme: &mut tab.theme,
default_font_size: 14.,
active_tab_id: &mut self.active_tab,
active_tab_id: None,
};
let terminal = TerminalView::new(ui, term_ctx, term_opt)
.set_focus(true)
Expand Down
9 changes: 4 additions & 5 deletions crates/egui-term/examples/themes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use copypasta::ClipboardContext;
use egui::{Id, Vec2};
use egui::Vec2;
use egui_term::{
ColorPalette, PtyEvent, Terminal, TerminalContext, TerminalFont, TerminalOptions,
TerminalTheme, TerminalView,
Expand All @@ -11,7 +11,6 @@ pub struct App {
terminal_font: TerminalFont,
terminal_theme: TerminalTheme,
multi_exec: bool,
active_id: Option<Id>,
clipboard: ClipboardContext,
pty_proxy_receiver: Receiver<(u64, PtyEvent)>,
}
Expand All @@ -25,7 +24,6 @@ impl App {
Self {
terminal_backend,
multi_exec: false,
active_id: None,
clipboard: ClipboardContext::new().unwrap(),
terminal_font: TerminalFont::default(),
terminal_theme: TerminalTheme::default(),
Expand Down Expand Up @@ -98,13 +96,14 @@ impl eframe::App for App {
});

egui::CentralPanel::default().show(ctx, |ui| {
let term_ctx = TerminalContext::new(&mut self.terminal_backend, &mut self.clipboard);
let term_ctx =
TerminalContext::new(&mut self.terminal_backend, &mut self.clipboard, &mut false);
let term_opt = TerminalOptions {
font: &mut self.terminal_font,
multi_exec: &mut self.multi_exec,
theme: &mut self.terminal_theme,
default_font_size: 14.,
active_tab_id: &mut self.active_id,
active_tab_id: None,
};
let terminal = TerminalView::new(ui, term_ctx, term_opt)
.set_focus(true)
Expand Down
93 changes: 60 additions & 33 deletions crates/egui-term/src/alacritty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::display::SftpExplorer;
use crate::errors::TermError;
use crate::ssh::{Pty, SshOptions};
use crate::ssh::{SshOptions, SshSession};
use crate::types::Size;
use alacritty_terminal::event::{Event, EventListener, Notify, OnResize, WindowSize};
use alacritty_terminal::event_loop::{EventLoop, Msg, Notifier};
Expand All @@ -22,6 +23,7 @@ use std::path::PathBuf;
use std::sync::mpsc::Sender;
use std::sync::{mpsc, Arc};
use tracing::debug;
use wezterm_ssh::Session;

pub type PtyEvent = Event;

Expand Down Expand Up @@ -138,6 +140,8 @@ pub enum TermType {

pub struct Terminal {
pub id: u64,
pub session: Option<SshSession>,
pub sftp_explorer: Option<SftpExplorer>,
pub url_regex: RegexSearch,
pub term: Arc<FairMutex<Term<EventProxy>>>,
pub size: TerminalSize,
Expand All @@ -152,37 +156,6 @@ impl PartialEq for Terminal {
}

impl Terminal {
pub fn new(
id: u64,
app_context: egui::Context,
term_type: TermType,
term_size: TerminalSize,
pty_event_proxy_sender: Sender<(u64, PtyEvent)>,
) -> Result<Self, TermError> {
match term_type {
TermType::Regular { working_directory } => {
let opts = Options {
working_directory,
..Default::default()
};
Self::new_with_pty(
id,
app_context,
term_size,
tty::new(&opts, term_size.into(), id)?,
pty_event_proxy_sender,
)
}
TermType::Ssh { options } => Self::new_with_pty(
id,
app_context,
term_size,
Pty::new(options)?,
pty_event_proxy_sender,
),
}
}

pub fn new_regular(
id: u64,
app_context: egui::Context,
Expand Down Expand Up @@ -214,6 +187,42 @@ impl Terminal {
)
}

fn new(
id: u64,
app_context: egui::Context,
term_type: TermType,
term_size: TerminalSize,
pty_event_proxy_sender: Sender<(u64, PtyEvent)>,
) -> Result<Self, TermError> {
match term_type {
TermType::Regular { working_directory } => {
let opts = Options {
working_directory,
..Default::default()
};
Self::new_with_pty(
id,
app_context,
term_size,
tty::new(&opts, term_size.into(), id)?,
pty_event_proxy_sender,
)
}
TermType::Ssh { options } => {
let session = SshSession::new(options)?;
let mut term = Self::new_with_pty(
id,
app_context,
term_size,
session.pty()?,
pty_event_proxy_sender,
)?;
term.session = Some(session);
Ok(term)
}
}
}

fn new_with_pty<Pty>(
id: u64,
app_context: egui::Context,
Expand Down Expand Up @@ -254,6 +263,8 @@ impl Terminal {
debug!("create a terminal backend: {id}");
Ok(Self {
id,
session: None,
sftp_explorer: None,
url_regex,
term,
size: term_size,
Expand All @@ -272,27 +283,43 @@ impl Drop for Terminal {
pub struct TerminalContext<'a> {
pub id: u64,
pub terminal: MutexGuard<'a, Term<EventProxy>>,
pub session: Option<&'a SshSession>,
pub sftp_explorer: &'a mut Option<SftpExplorer>,
pub url_regex: &'a mut RegexSearch,
pub size: &'a mut TerminalSize,
pub notifier: &'a mut Notifier,
pub hovered_hyperlink: &'a mut Option<Match>,
pub clipboard: &'a mut ClipboardContext,
pub show_sftp_window: &'a mut bool,
}

impl<'a> TerminalContext<'a> {
pub fn new(terminal: &'a mut Terminal, clipboard: &'a mut ClipboardContext) -> Self {
pub fn new(
terminal: &'a mut Terminal,
clipboard: &'a mut ClipboardContext,
show_sftp_window: &'a mut bool,
) -> Self {
let term = terminal.term.lock();
Self {
id: terminal.id,
terminal: term,
session: terminal.session.as_ref(),
sftp_explorer: &mut terminal.sftp_explorer,
url_regex: &mut terminal.url_regex,
size: &mut terminal.size,
notifier: &mut terminal.notifier,
hovered_hyperlink: &mut terminal.hovered_hyperlink,
show_sftp_window,
clipboard,
}
}

pub fn open_sftp(&mut self, session: &Session) -> Result<(), TermError> {
let sftp = session.sftp();
*self.sftp_explorer = Some(SftpExplorer::new(sftp)?);
Ok(())
}

pub fn term_mode(&self) -> TermMode {
*self.terminal.mode()
}
Expand Down
Loading
Loading