LunarEvent

MoonBit terminal event API backed by TerminalEvent C FFI

terminal
event
tui
moon add FrozenLemonTee/LunarEvent@0.1.1
Download zip
Version
0.1.1
License
Apache-2.0
Last updated
2 months ago
Downloads
95
README

#LunarEvent

LunarEvent is a MoonBit-friendly terminal event layer backed by the stable C FFI surface published by TerminalEvent.

It keeps the C and C++ implementation boundary outside downstream MoonBit projects. Applications import MoonBit packages only; they do not include or reference TerminalEvent's C++ headers or source files.

#Package Boundary

  • FrozenLemonTee/TerminalEvent/moonbit/lte_native owns the raw lte_* C ABI binding.
  • FrozenLemonTee/LunarEvent maps the raw ABI into MoonBit Event and EventBackend types.
  • FrozenLemonTee/LunarEvent/lunartui adapts LunarEvent events into LunarTUI @base.Event values.
  • FrozenLemonTee/LunarTUI remains independent from LunarEvent and TerminalEvent.

The dependency direction is intentionally one-way at each layer:

TerminalEvent C++ core -> TerminalEvent C ABI -> TerminalEvent MoonBit FFI -> LunarEvent -> LunarTUI adapter -> application

#Installation

moon add FrozenLemonTee/LunarEvent

Or add it manually to moon.mod:

import {
"FrozenLemonTee/LunarEvent@0.1.0",
}

LunarEvent currently targets MoonBit native builds.

#Core Event API

The root package exposes a terminal event model that is independent from LunarTUI widgets:

  • Event::Key(KeyEvent) for keyboard input.
  • Event::Resize(ResizeEvent) for terminal size changes.
  • Event::Paste(String) for pasted text.
  • Event::Mouse(MouseEvent) for mouse activity.
  • Event::Focus(FocusEvent) for focus gained/lost notifications.
  • Event::Unknown(String) for raw input that the backend could not classify.

EventBackend owns the runtime bridge to TerminalEvent's C FFI:

let backend = @LunarEvent.EventBackend::new()
match backend.enter_raw_mode() {
Ok(_) => {
match backend.poll_event(32) {
Some(event) => {
// Route the event into your application.
ignore(event)
}
None => ()
}
backend.restore_terminal()
}
Err(_) => ()
}
backend.shutdown()

The timeout passed to poll_event is in milliseconds. None means no event was available or the backend reported no event.

#LunarTUI Adapter

The lunartui subpackage is the default bridge for LunarTUI applications:

let source = @lunartui.EventSource::new()
match source.enter_raw_mode() {
Ok(_) => {
match source.poll_event(32) {
Some(event) => {
// event is a LunarTUI @base.Event
ignore(event)
}
None => ()
}
source.restore_terminal()
}
Err(_) => ()
}
source.shutdown()

The adapter maps LunarEvent values into LunarTUI's terminal-agnostic event protocol:

LunarEventLunarTUI
Event::Key@base.Event::key
Event::Resize@base.Event::resize
Event::Paste@base.Event::text_input
Event::Mouse@base.Event::mouse
Event::Focus@base.Event::focus
Event::Unknowndropped by the adapter

#Backend Notes

The current TerminalEvent backend is POSIX-oriented. On Windows, raw mode may report unavailable unless the program is executed in a compatible POSIX terminal environment.

  • TerminalEvent: C++ terminal event backend and C ABI.
  • LunarTUI: MoonBit TUI widgets, layouts, rendering, and event protocol.
  • TextEditor: interactive demo using TerminalEvent, LunarEvent, and LunarTUI together.

#
Event

pub(all) enum Event {
Key(KeyEvent)
Resize(ResizeEvent)
Paste(String)
Mouse(MouseEvent)
Focus(FocusEvent)
Unknown(String)
} derive(Eq)

#
EventBackend

pub struct EventBackend {
}

#
EventBackend::enter_raw_mode

fn EventBackend::enter_raw_mode(self : EventBackend) -> Result[Unit, TerminalError]

#
EventBackend::new

#
EventBackend::poll_event

fn EventBackend::poll_event(self : EventBackend, timeout_ms : Int) -> Event?

#
EventBackend::restore_terminal

fn EventBackend::restore_terminal(self : EventBackend) -> Unit

#
EventBackend::shutdown

fn EventBackend::shutdown(self : EventBackend) -> Unit

#
EventBackend::terminal_size

fn EventBackend::terminal_size(self : EventBackend) -> Result[Size, TerminalError]

#
EventStream

pub struct EventStream {
buf : Array[Event]
}

impl Add for EventStream

#
EventStream::add

fn EventStream::add(self : EventStream, event : Event) -> EventStream

#
EventStream::add_all

fn EventStream::add_all(self : EventStream, stream : Array[Event]) -> EventStream

#
EventStream::new

fn EventStream::new(stream : Array[Event]) -> EventStream

#
FocusEvent

pub(all) struct FocusEvent {
state : FocusState
} derive(Eq)

#
FocusState

pub(all) enum FocusState {
Gained
Lost
} derive(Eq)

#
KeyCode

pub(all) enum KeyCode {
Character
Enter
Escape
Backspace
Tab
Left
Right
Up
Down
Home
End
PageUp
PageDown
Insert
Delete
Function(Int)
Unknown
} derive(Eq)

#
KeyEvent

pub(all) struct KeyEvent {
code : KeyCode
text : String?
modifiers : Modifiers
} derive(Eq)

#
Modifiers

pub(all) struct Modifiers {
shift : Bool
ctrl : Bool
alt : Bool
meta : Bool
} derive(Eq)

#
Modifiers::new

fn Modifiers::new(shift? : Bool, ctrl? : Bool, alt? : Bool, meta? : Bool) -> Modifiers

#
MouseAction

pub(all) enum MouseAction {
Move
Down
Up
Drag
Scroll
Unknown
} derive(Eq)

#
MouseButton

pub(all) enum MouseButton {
Left
Right
Middle
Back
Forward
Unknown
} derive(Eq)

#
MouseEvent

pub(all) struct MouseEvent {
button : MouseButton
action : MouseAction
x : Int
y : Int
modifiers : Modifiers
} derive(Eq)

#
ResizeEvent

pub(all) struct ResizeEvent {
width : Int
height : Int
} derive(Eq)

#
Size

pub(all) struct Size {
width : Int
height : Int
} derive(Eq)

#
TerminalError

pub(all) enum TerminalError {
NativeError(Int)
} derive(Eq)

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io