Skip to content

Commit 2b14da0

Browse files
authored
Handle logs coming in from forked process (#762)
1 parent 25f725f commit 2b14da0

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,18 @@ Flyline is similar to [ble.sh](https://github.com/akinomyoga/ble.sh) but is writ
3838

3939
# Installation
4040

41+
> [!IMPORTANT]
42+
> After installing, run `flyline run-tutorial` and if you don't like the mouse capturing: `flyline mouse --mode disabled`
43+
4144
### Quick install: `install.sh`
4245

4346
> [!TIP]
4447
> Run the following command to download flyline and update your `.bashrc` to load the latest version. No need for `sudo`!
48+
4549
```bash
4650
curl -sSfL https://github.com/HalFrgrd/flyline/releases/latest/download/install.sh | sh
4751
```
48-
49-
50-
> [!IMPORTANT]
51-
> On macOS you must first install a version of bash that supports custom builtins: `brew install bash`
52+
On macOS you must first install a version of Bash that supports custom builtins: `brew install bash`
5253

5354
### Download from releases
5455

src/app/tab_completion.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,8 @@ impl App<'_> {
12411241

12421242
if pid == 0 {
12431243
// Child process
1244+
crate::logging::disable_streaming();
1245+
crate::logging::clear_logs();
12441246
unsafe {
12451247
libc::setsid();
12461248
// Reset common signals to default so the child process terminates cleanly and instantly on signals.
@@ -1274,7 +1276,10 @@ impl App<'_> {
12741276
);
12751277
let elapsed = thread_start.elapsed();
12761278

1277-
let data = result.map(|r| (r, elapsed));
1279+
log::info!("Child process completed");
1280+
let child_logs = crate::logging::take_logs();
1281+
1282+
let data = (result.map(|r| (r, elapsed)), child_logs);
12781283
if let Ok(serialized) = serde_json::to_vec(&data) {
12791284
let mut file = unsafe { std::fs::File::from_raw_fd(write_fd) };
12801285
use std::io::Write;
@@ -1289,8 +1294,6 @@ impl App<'_> {
12891294
}
12901295
}
12911296

1292-
log::info!("Child process completed");
1293-
12941297
// Use _exit to avoid running atexit handlers in the child process.
12951298
unsafe {
12961299
libc::_exit(0);
@@ -1307,18 +1310,33 @@ impl App<'_> {
13071310
.spawn(move || {
13081311
let mut file = unsafe { std::fs::File::from_raw_fd(read_fd) };
13091312
let mut len_buf = [0u8; 8];
1310-
let res = if std::io::Read::read_exact(&mut file, &mut len_buf).is_err() {
1313+
let payload: Option<(
1314+
Option<(ActiveSuggestionsBuilder, std::time::Duration)>,
1315+
Vec<String>,
1316+
)> = if std::io::Read::read_exact(&mut file, &mut len_buf).is_err() {
13111317
None
13121318
} else {
13131319
let len = u64::from_ne_bytes(len_buf);
13141320
let mut data_buf = vec![0u8; len as usize];
13151321
if std::io::Read::read_exact(&mut file, &mut data_buf).is_ok() {
1316-
serde_json::from_slice(&data_buf).ok().flatten()
1322+
serde_json::from_slice(&data_buf).ok()
13171323
} else {
13181324
None
13191325
}
13201326
};
1321-
let _ = tx.send(res);
1327+
1328+
let (completion_res, child_logs) = if let Some((res, logs)) = payload {
1329+
(res, logs)
1330+
} else {
1331+
(None, vec![])
1332+
};
1333+
1334+
// Replay child logs inside the parent process
1335+
for log_line in child_logs {
1336+
crate::logging::log_raw_entry(log_line);
1337+
}
1338+
1339+
let _ = tx.send(completion_res);
13221340

13231341
// Reap the child process to prevent zombie processes
13241342
unsafe {

src/app/ui.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,9 @@ impl<'a> App<'a> {
446446
content.newline();
447447
}
448448

449-
if !self.mouse_state.is_enabled() {
449+
if !self.mouse_state.is_enabled()
450+
&& self.settings.mouse_mode != crate::settings::MouseMode::Disabled
451+
{
450452
let red = Style::default().fg(Color::Red).slow_blink();
451453
let escape_hint = TaggedLine::from(vec![TaggedSpan::new(
452454
Span::styled("Press Escape to re-enable mouse mode.", red),

src/logging.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,41 @@ pub fn dump_logs_stdout() -> Result<()> {
147147
Ok(())
148148
}
149149

150+
/// Clear all in-memory logs.
151+
pub fn clear_logs() {
152+
if let Some(logger) = LOGGER.get() {
153+
let mut entries = logger.entries.lock().unwrap();
154+
entries.clear();
155+
}
156+
}
157+
158+
/// Disable direct file/terminal log streaming (used in child processes to prevent double-logging).
159+
pub fn disable_streaming() {
160+
if let Some(logger) = LOGGER.get() {
161+
let mut stream_writer = logger.stream_writer.lock().unwrap();
162+
*stream_writer = None;
163+
}
164+
TERMINAL_STREAMING.store(false, Ordering::Relaxed);
165+
}
166+
167+
/// Retrieve all in-memory log entries and clear the buffer.
168+
pub fn take_logs() -> Vec<String> {
169+
if let Some(logger) = LOGGER.get() {
170+
let mut entries = logger.entries.lock().unwrap();
171+
std::mem::take(&mut *entries).into()
172+
} else {
173+
vec![]
174+
}
175+
}
176+
177+
/// Write a pre-formatted raw log entry directly into the log buffers/streams.
178+
pub fn log_raw_entry(entry: String) {
179+
if let Some(logger) = LOGGER.get() {
180+
logger.write_stream_entry(&entry);
181+
logger.push(entry);
182+
}
183+
}
184+
150185
/// Print all in-memory log entries to stderr (used for diagnostic error paths).
151186
pub fn print_logs_stderr() {
152187
if let Some(logger) = LOGGER.get() {

0 commit comments

Comments
 (0)