Skip to content
Merged
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
9 changes: 6 additions & 3 deletions src/cursor/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use std::{
};

use crate::{
event::{filter::CursorPositionFilter, poll_internal, read_internal, InternalEvent},
event::{
filter::CursorPositionFilter,
internal::{self, InternalEvent},
},
terminal::{disable_raw_mode, enable_raw_mode, sys::is_raw_mode_enabled},
};

Expand Down Expand Up @@ -36,10 +39,10 @@ fn read_position_raw() -> io::Result<(u16, u16)> {
stdout.flush()?;

loop {
match poll_internal(Some(Duration::from_millis(2000)), &CursorPositionFilter) {
match internal::poll(Some(Duration::from_millis(2000)), &CursorPositionFilter) {
Ok(true) => {
if let Ok(InternalEvent::CursorPosition(x, y)) =
read_internal(&CursorPositionFilter)
internal::read(&CursorPositionFilter)
{
return Ok((x, y));
}
Expand Down
79 changes: 5 additions & 74 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
//! them (`event-*`).

pub(crate) mod filter;
pub(crate) mod internal;
pub(crate) mod read;
pub(crate) mod source;
#[cfg(feature = "event-stream")]
Expand All @@ -131,37 +132,13 @@ use derive_more::derive::IsVariant;
#[cfg(feature = "event-stream")]
pub use stream::EventStream;

use crate::event::{
filter::{EventFilter, Filter},
read::InternalEventReader,
timeout::PollTimeout,
};
use crate::{csi, Command};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use crate::{csi, event::filter::EventFilter, Command};
use std::fmt::{self, Display};
use std::time::Duration;

use bitflags::bitflags;
use std::hash::{Hash, Hasher};

/// Static instance of `InternalEventReader`.
/// This needs to be static because there can be one event reader.
static INTERNAL_EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);

pub(crate) fn lock_internal_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
MutexGuard::map(INTERNAL_EVENT_READER.lock(), |reader| {
reader.get_or_insert_with(InternalEventReader::default)
})
}
fn try_lock_internal_event_reader_for(
duration: Duration,
) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
Some(MutexGuard::map(
INTERNAL_EVENT_READER.try_lock_for(duration)?,
|reader| reader.get_or_insert_with(InternalEventReader::default),
))
}

/// Checks if there is an [`Event`](enum.Event.html) available.
///
/// Returns `Ok(true)` if an [`Event`](enum.Event.html) is available otherwise it returns `Ok(false)`.
Expand Down Expand Up @@ -202,7 +179,7 @@ fn try_lock_internal_event_reader_for(
/// }
/// ```
pub fn poll(timeout: Duration) -> std::io::Result<bool> {
poll_internal(Some(timeout), &EventFilter)
internal::poll(Some(timeout), &EventFilter)
}

/// Reads a single [`Event`](enum.Event.html).
Expand Down Expand Up @@ -247,40 +224,13 @@ pub fn poll(timeout: Duration) -> std::io::Result<bool> {
/// }
/// ```
pub fn read() -> std::io::Result<Event> {
match read_internal(&EventFilter)? {
InternalEvent::Event(event) => Ok(event),
match internal::read(&EventFilter)? {
internal::InternalEvent::Event(event) => Ok(event),
#[cfg(unix)]
_ => unreachable!(),
}
}

/// Polls to check if there are any `InternalEvent`s that can be read within the given duration.
pub(crate) fn poll_internal<F>(timeout: Option<Duration>, filter: &F) -> std::io::Result<bool>
where
F: Filter,
{
let (mut reader, timeout) = if let Some(timeout) = timeout {
let poll_timeout = PollTimeout::new(Some(timeout));
if let Some(reader) = try_lock_internal_event_reader_for(timeout) {
(reader, poll_timeout.leftover())
} else {
return Ok(false);
}
} else {
(lock_internal_event_reader(), None)
};
reader.poll(timeout, filter)
}

/// Reads a single `InternalEvent`.
pub(crate) fn read_internal<F>(filter: &F) -> std::io::Result<InternalEvent>
where
F: Filter,
{
let mut reader = lock_internal_event_reader();
reader.read(filter)
}

bitflags! {
/// Represents special flags that tell compatible terminals to add extra information to keyboard events.
///
Expand Down Expand Up @@ -1467,25 +1417,6 @@ impl Display for KeyCode {
}
}

/// An internal event.
///
/// Encapsulates publicly available `Event` with additional internal
/// events that shouldn't be publicly available to the crate users.
#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)]
pub(crate) enum InternalEvent {
/// An event.
Event(Event),
/// A cursor position (`col`, `row`).
#[cfg(unix)]
CursorPosition(u16, u16),
/// The progressive keyboard enhancement flags enabled by the terminal.
#[cfg(unix)]
KeyboardEnhancementFlags(KeyboardEnhancementFlags),
/// Attributes and architectural class of the terminal.
#[cfg(unix)]
PrimaryDeviceAttributes,
}

#[cfg(test)]
mod tests {
use std::collections::hash_map::DefaultHasher;
Expand Down
2 changes: 1 addition & 1 deletion src/event/filter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::event::InternalEvent;
use crate::event::internal::InternalEvent;

/// Interface for filtering an `InternalEvent`.
pub(crate) trait Filter: Send + Sync + 'static {
Expand Down
72 changes: 72 additions & 0 deletions src/event/internal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::time::Duration;

use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};

#[cfg(unix)]
use crate::event::KeyboardEnhancementFlags;
use crate::event::{filter::Filter, read::InternalEventReader, timeout::PollTimeout, Event};

/// Static instance of `InternalEventReader`.
/// This needs to be static because there can be one event reader.
static EVENT_READER: Mutex<Option<InternalEventReader>> = parking_lot::const_mutex(None);

pub(crate) fn lock_event_reader() -> MappedMutexGuard<'static, InternalEventReader> {
MutexGuard::map(EVENT_READER.lock(), |reader| {
reader.get_or_insert_with(InternalEventReader::default)
})
}

fn try_lock_event_reader_for(
duration: Duration,
) -> Option<MappedMutexGuard<'static, InternalEventReader>> {
Some(MutexGuard::map(
EVENT_READER.try_lock_for(duration)?,
|reader| reader.get_or_insert_with(InternalEventReader::default),
))
}

/// Polls to check if there are any `InternalEvent`s that can be read within the given duration.
pub(crate) fn poll<F>(timeout: Option<Duration>, filter: &F) -> std::io::Result<bool>
where
F: Filter,
{
let (mut reader, timeout) = if let Some(timeout) = timeout {
let poll_timeout = PollTimeout::new(Some(timeout));
if let Some(reader) = try_lock_event_reader_for(timeout) {
(reader, poll_timeout.leftover())
} else {
return Ok(false);
}
} else {
(lock_event_reader(), None)
};
reader.poll(timeout, filter)
}

/// Reads a single `InternalEvent`.
pub(crate) fn read<F>(filter: &F) -> std::io::Result<InternalEvent>
where
F: Filter,
{
let mut reader = lock_event_reader();
reader.read(filter)
}

/// An internal event.
///
/// Encapsulates publicly available `Event` with additional internal
/// events that shouldn't be publicly available to the crate users.
#[derive(Debug, PartialOrd, PartialEq, Hash, Clone, Eq)]
pub(crate) enum InternalEvent {
/// An event.
Event(Event),
/// A cursor position (`col`, `row`).
#[cfg(unix)]
CursorPosition(u16, u16),
/// The progressive keyboard enhancement flags enabled by the terminal.
#[cfg(unix)]
KeyboardEnhancementFlags(KeyboardEnhancementFlags),
/// Attributes and architectural class of the terminal.
#[cfg(unix)]
PrimaryDeviceAttributes,
}
4 changes: 3 additions & 1 deletion src/event/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::event::source::unix::UnixInternalEventSource;
use crate::event::source::windows::WindowsEventSource;
#[cfg(feature = "event-stream")]
use crate::event::sys::Waker;
use crate::event::{filter::Filter, source::EventSource, timeout::PollTimeout, InternalEvent};
use crate::event::{
filter::Filter, internal::InternalEvent, source::EventSource, timeout::PollTimeout,
};

/// Can be used to read `InternalEvent`s.
pub(crate) struct InternalEventReader {
Expand Down
2 changes: 1 addition & 1 deletion src/event/source.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{io, time::Duration};

use super::internal::InternalEvent;
#[cfg(feature = "event-stream")]
use super::sys::Waker;
use super::InternalEvent;

#[cfg(unix)]
pub(crate) mod unix;
Expand Down
3 changes: 2 additions & 1 deletion src/event/source/unix/mio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use signal_hook_mio::v1_0::Signals;
#[cfg(feature = "event-stream")]
use crate::event::sys::Waker;
use crate::event::{
source::EventSource, sys::unix::parse::parse_event, timeout::PollTimeout, Event, InternalEvent,
internal::InternalEvent, source::EventSource, sys::unix::parse::parse_event,
timeout::PollTimeout, Event,
};
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};

Expand Down
2 changes: 1 addition & 1 deletion src/event/source/unix/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use filedescriptor::{poll, pollfd, POLLIN};

#[cfg(feature = "event-stream")]
use crate::event::sys::Waker;
use crate::event::{source::EventSource, sys::unix::parse::parse_event, InternalEvent};
use crate::event::{internal::InternalEvent, source::EventSource, sys::unix::parse::parse_event};
use crate::terminal::sys::file_descriptor::{tty_fd, FileDesc};

/// Holds a prototypical Waker and a receiver we can wait on when doing select().
Expand Down
2 changes: 1 addition & 1 deletion src/event/source/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ use crate::event::{
#[cfg(feature = "event-stream")]
use crate::event::sys::Waker;
use crate::event::{
internal::InternalEvent,
source::EventSource,
sys::windows::parse::{handle_key_event, handle_mouse_event},
timeout::PollTimeout,
InternalEvent,
};

pub(crate) struct WindowsEventSource {
Expand Down
14 changes: 8 additions & 6 deletions src/event/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use std::{
use futures_core::stream::Stream;

use crate::event::{
filter::EventFilter, lock_internal_event_reader, poll_internal, read_internal, sys::Waker,
Event, InternalEvent,
filter::EventFilter,
internal::{self, InternalEvent},
sys::Waker,
Event,
};

/// A stream of `Result<Event>`.
Expand Down Expand Up @@ -44,7 +46,7 @@ impl Default for EventStream {
thread::spawn(move || {
while let Ok(task) = receiver.recv() {
loop {
if let Ok(true) = poll_internal(None, &EventFilter) {
if let Ok(true) = internal::poll(None, &EventFilter) {
break;
}

Expand All @@ -59,7 +61,7 @@ impl Default for EventStream {
});

EventStream {
poll_internal_waker: lock_internal_event_reader().waker(),
poll_internal_waker: internal::lock_event_reader().waker(),
stream_wake_task_executed: Arc::new(AtomicBool::new(false)),
stream_wake_task_should_shutdown: Arc::new(AtomicBool::new(false)),
task_sender,
Expand Down Expand Up @@ -102,8 +104,8 @@ impl Stream for EventStream {
type Item = io::Result<Event>;

fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let result = match poll_internal(Some(Duration::from_secs(0)), &EventFilter) {
Ok(true) => match read_internal(&EventFilter) {
let result = match internal::poll(Some(Duration::from_secs(0)), &EventFilter) {
Ok(true) => match internal::read(&EventFilter) {
Ok(InternalEvent::Event(event)) => Poll::Ready(Some(Ok(event))),
Err(e) => Poll::Ready(Some(Err(e))),
#[cfg(unix)]
Expand Down
2 changes: 1 addition & 1 deletion src/event/sys/unix/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::event::{
MediaKeyCode, ModifierKeyCode, MouseButton, MouseEvent, MouseEventKind,
};

use super::super::super::InternalEvent;
use crate::event::internal::InternalEvent;

// Event parsing
//
Expand Down
8 changes: 4 additions & 4 deletions src/terminal/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
ws_ypixel: 0,
};

let file = File::open("/dev/tty").map(|file| (FileDesc::new(file.into_raw_fd(), true)));

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 70 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body
let fd = if let Ok(file) = &file {
file.raw_fd()
} else {
Expand All @@ -84,7 +84,7 @@

#[cfg(not(feature = "libc"))]
pub(crate) fn window_size() -> io::Result<WindowSize> {
let file = File::open("/dev/tty").map(|file| (FileDesc::Owned(file.into())));

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on ubuntu-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body

Check warning on line 87 in src/terminal/sys/unix.rs

View workflow job for this annotation

GitHub Actions / nightly on macOS-latest

unnecessary parentheses around closure body
let fd = if let Ok(file) = &file {
file.as_fd()
} else {
Expand Down Expand Up @@ -214,7 +214,7 @@
fn query_keyboard_enhancement_flags_raw() -> io::Result<Option<KeyboardEnhancementFlags>> {
use crate::event::{
filter::{KeyboardEnhancementFlagsFilter, PrimaryDeviceAttributesFilter},
poll_internal, read_internal, InternalEvent,
internal::{self, InternalEvent},
};
use std::io::Write;
use std::time::Duration;
Expand All @@ -241,15 +241,15 @@
}

loop {
match poll_internal(
match internal::poll(
Some(Duration::from_millis(2000)),
&KeyboardEnhancementFlagsFilter,
) {
Ok(true) => {
match read_internal(&KeyboardEnhancementFlagsFilter) {
match internal::read(&KeyboardEnhancementFlagsFilter) {
Ok(InternalEvent::KeyboardEnhancementFlags(current_flags)) => {
// Flush the PrimaryDeviceAttributes out of the event queue.
read_internal(&PrimaryDeviceAttributesFilter).ok();
internal::read(&PrimaryDeviceAttributesFilter).ok();
return Ok(Some(current_flags));
}
_ => return Ok(None),
Expand Down
Loading