Skip to content
Closed
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
47 changes: 44 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions crates/fig_util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,24 @@ workspace = true
default = []

[dependencies]
anyhow.workspace = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a fan of adding all of these dependencies to a foundational crate in our workspace like fig_util, e.g. nix doesn't make sense here considering it's not for Windows

shlex.workspace = true
async-trait.workspace = true
camino.workspace = true
cfg-if.workspace = true
clap.workspace = true
crossterm.workspace = true
dirs.workspace = true
fig_os_shim.workspace = true
hex.workspace = true
indoc.workspace = true
libc.workspace = true
paste = "1.0.11"
portable-pty.workspace = true
termios = "0.3"
nix = "0.26"
filedescriptor = "0.8.3"
console = "0.15.11"
rand.workspace = true
regex.workspace = true
serde.workspace = true
Expand Down
10 changes: 5 additions & 5 deletions crates/fig_util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
pub mod consts;
pub mod directories;
#[cfg(target_os = "macos")]
pub mod launchd_plist;
pub mod manifest;
mod open;
pub mod process_info;
mod shell;
pub mod pty;
pub mod shell;
pub mod system_info;
pub mod terminal;

pub mod consts;
#[cfg(target_os = "macos")]
pub mod launchd_plist;

use std::cmp::Ordering;
use std::path::{
Path,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
59 changes: 58 additions & 1 deletion crates/fig_util/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ use std::borrow::Cow;
use std::fmt;
use std::sync::OnceLock;

use crossterm::event::{
KeyCode,
KeyEvent,
KeyModifiers,
};
use fig_os_shim::Context;
use portable_pty::PtySize;
use serde::{
Deserialize,
Serialize,
};

/// Terminals that macOS supports
pub const MACOS_TERMINALS: &[Terminal] = &[
Terminal::Alacritty,
Expand Down Expand Up @@ -793,6 +798,58 @@ impl IntelliJVariant {
}
}

pub fn get_terminal_size() -> PtySize {
match crossterm::terminal::size() {
Ok((cols, rows)) => PtySize {
rows,
cols,
pixel_width: 0,
pixel_height: 0,
},
Err(_) => {
// Fall back to default size
PtySize {
rows: 24,
cols: 80,
pixel_width: 0,
pixel_height: 0,
}
},
}
}

pub fn key_event_to_bytes(key: KeyEvent) -> Vec<u8> {
match key.code {
KeyCode::Char(c) => {
// Handle Ctrl+key combinations
if key.modifiers.contains(KeyModifiers::CONTROL) {
// Convert to control character (ASCII control chars are 1-26)
if c.is_ascii_lowercase() {
return vec![(c as u8) - b'a' + 1];
} else if c.is_ascii_uppercase() {
return vec![(c as u8) - b'A' + 1];
}
}
// Regular character
c.to_string().into_bytes()
},
KeyCode::Enter => vec![b'\r'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a non-exhaustive list. Is there an API can that do this for us?

KeyCode::Backspace => vec![b'\x7f'],
KeyCode::Esc => vec![b'\x1b'],
KeyCode::Tab => vec![b'\t'],
KeyCode::Up => vec![b'\x1b', b'[', b'A'],
KeyCode::Down => vec![b'\x1b', b'[', b'B'],
KeyCode::Right => vec![b'\x1b', b'[', b'C'],
KeyCode::Left => vec![b'\x1b', b'[', b'D'],
KeyCode::Home => vec![b'\x1b', b'[', b'H'],
KeyCode::End => vec![b'\x1b', b'[', b'F'],
KeyCode::Delete => vec![b'\x1b', b'[', b'3', b'~'],
KeyCode::PageUp => vec![b'\x1b', b'[', b'5', b'~'],
KeyCode::PageDown => vec![b'\x1b', b'[', b'6', b'~'],
_ => vec![], // Ignore other keys for now
}
}

#[cfg(test)]
mod tests {
use std::sync::Arc;
Expand Down
20 changes: 10 additions & 10 deletions crates/figterm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub mod interceptor;
pub mod ipc;
pub mod logger;
mod message;
pub mod pty;
pub mod term;
pub mod update;

Expand Down Expand Up @@ -79,6 +78,15 @@ use fig_util::process_info::{
Pid,
PidExt,
};
#[cfg(unix)]
use fig_util::pty::unix::open_pty;
#[cfg(windows)]
use fig_util::pty::win::open_pty;
use fig_util::pty::{
AsyncMasterPty,
AsyncMasterPtyExt,
CommandBuilder,
};
use fig_util::{
PRODUCT_NAME,
PTY_BINARY_NAME,
Expand Down Expand Up @@ -126,14 +134,6 @@ use crate::message::{
process_figterm_message,
process_remote_message,
};
#[cfg(unix)]
use crate::pty::unix::open_pty;
#[cfg(windows)]
use crate::pty::win::open_pty;
use crate::pty::{
AsyncMasterPtyExt,
CommandBuilder,
};
use crate::term::{
SystemTerminal,
Terminal,
Expand Down Expand Up @@ -239,7 +239,7 @@ async fn _should_install_remote_ssh_integration(
remote_receiver: Receiver<fig_proto::remote::Clientbound>,
remote_sender: Sender<Hostbound>,
term: &Term<EventHandler>,
pty_master: &mut Box<dyn crate::pty::AsyncMasterPty + Send + Sync>,
pty_master: &mut Box<dyn AsyncMasterPty + Send + Sync>,
key_interceptor: &mut KeyInterceptor,
) -> Option<bool> {
use fig_proto::remote::clientbound;
Expand Down
2 changes: 1 addition & 1 deletion crates/figterm/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use fig_proto::remote::{
hostbound,
};
use fig_util::env_var::PROCESS_LAUNCHED_BY_Q;
use fig_util::pty::AsyncMasterPty;
use flume::Sender;
use tokio::process::Command;
use tracing::{
Expand All @@ -47,7 +48,6 @@ use tracing::{
use crate::event_handler::EventHandler;
use crate::history::HistorySender;
use crate::interceptor::KeyInterceptor;
use crate::pty::AsyncMasterPty;
use crate::{
EXPECTED_BUFFER,
INSERT_ON_NEW_CMD,
Expand Down
1 change: 1 addition & 0 deletions crates/q_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ indoc.workspace = true
mimalloc.workspace = true
owo-colors = "4.2.0"
parking_lot.workspace = true
portable-pty.workspace = true
rand.workspace = true
regex.workspace = true
rustyline = { version = "15.0.0", features = ["derive", "custom-bindings"] }
Expand Down
32 changes: 8 additions & 24 deletions crates/q_cli/src/cli/chat/hooks.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::collections::HashMap;
use std::io::Write;
use std::process::Stdio;
use std::time::{
Duration,
Instant,
};

use bstr::ByteSlice;
use crossterm::style::{
Color,
Stylize,
Expand Down Expand Up @@ -35,7 +33,7 @@ use spinners::{
Spinners,
};

use super::util::truncate_safe;
use super::tools::execute_bash::ExecuteBash;

const DEFAULT_TIMEOUT_MS: u64 = 30_000;
const DEFAULT_MAX_OUTPUT_SIZE: usize = 1024 * 10;
Expand Down Expand Up @@ -294,34 +292,20 @@ impl HookExecutor {

async fn execute_inline_hook(&self, hook: &Hook) -> Result<String> {
let command = hook.command.as_ref().ok_or_else(|| eyre!("no command specified"))?;
let execute_bash = ExecuteBash {
command: command.clone(),
};

let command_future = tokio::process::Command::new("bash")
.arg("-c")
.arg(command)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output();
let command_future = execute_bash.execute_pty_without_input(hook.max_output_size, false);
let timeout = Duration::from_millis(hook.timeout_ms);

// Run with timeout
match tokio::time::timeout(timeout, command_future).await {
Ok(result) => {
let result = result?;
if result.status.success() {
let stdout = result.stdout.to_str_lossy();
let stdout = format!(
"{}{}",
truncate_safe(&stdout, hook.max_output_size),
if stdout.len() > hook.max_output_size {
" ... truncated"
} else {
""
}
);
Ok(stdout)
} else {
Err(eyre!("command returned non-zero exit code: {}", result.status))
match result.exit_status {
0 => Ok(result.stdout),
code => Err(eyre!("command returned non-zero exit code: {}", code)),
}
},
Err(_) => Err(eyre!("command timed out after {} ms", timeout.as_millis())),
Expand Down
Loading
Loading