glk-rs ====== This crate provides bindings to implement the Glk I/O interface for hosting interactive fiction interpreters. This standard is used by, for example, the glulxe interpreter. It exports the C functions, rust traits and a dummy implementation. It is up to the user of this crate to provide actual implementations for the Glk functions that the interpreter will invoke. - [Glk specification 0.7.5](https://www.eblong.com/zarf/glk/glk-spec-075.html) ## Note This crate currently only has the capability to *provide* a Glk library. When implementing an interpreter or other Glk application it would be useful to *use* a Glk library, this is currently not possible with this crate, though it could likely share some of the traits, utility code, or constants at least. ## How to use Implement the trait `glk::traits::Api` and Glk traits (at least `Base`, which handles the base functionality; every Glk module is handled by a separate trait) on a structure with handlers, then call `glk::init(…)` to register the handlers. ```rust /** Dispatch trait for all Glk APIs. Each function returns a * reference to a trait which will be called for functions on the associated * Glk module. */ pub trait Api { /** Mandatory Glk API functions. */ fn base(&mut self) -> &mut dyn Base; /** GLK_MODULE_LINE_ECHO */ fn line_echo(&mut self) -> Option<&mut dyn LineEcho>; /** GLK_MODULE_LINE_TERMINATORS */ fn line_terminators(&mut self) -> Option<&mut dyn LineTerminators>; /** GLK_MODULE_UNICODE */ fn unicode(&mut self) -> Option<&mut dyn Unicode>; /** GLK_MODULE_UNICODE_NORM */ fn unicode_norm(&mut self) -> Option<&mut dyn UnicodeNorm>; /** GLK_MODULE_IMAGE */ fn image(&mut self) -> Option<&mut dyn Image>; /** GLK_MODULE_SOUND */ fn sound(&mut self) -> Option<&mut dyn Sound>; /** GLK_MODULE_SOUND2 */ fn sound2(&mut self) -> Option<&mut dyn Sound2>; /** GLK_MODULE_HYPERLINKS */ fn hyperlinks(&mut self) -> Option<&mut dyn Hyperlinks>; /** GLK_MODULE_DATETIME */ fn date_time(&mut self) -> Option<&mut dyn Datetime>; /** GLK_MODULE_RESOURCE_STREAM */ fn resource_stream(&mut self) -> Option<&mut dyn ResourceStream>; /** GLK_MODULE_GARGLKTEXT */ fn garglk_text(&mut self) -> Option<&mut dyn garglk::GarGlkText>; /** GI blorb handler functions */ fn giblorb(&mut self) -> Option<&mut dyn giblorb::Handlers>; /** GI dispatch handler functions */ fn gidispatch(&mut self) -> Option<&mut dyn gidispatch::Handlers>; /** Rust Glk extension handler functions */ fn ext(&mut self) -> Option<&mut dyn ext::Handlers>; } ``` These functions could return `Some(self)`, or delegate to a different object that implements the given trait. Or return `None` if the module is left unimplemented. Then link your application to whatever needs the `glk_` API. Note that the handlers registered with `glk::init` are local to a thread, so make sure to call the interpreter from the same thread that registers the glk API handlers. Glk only supports single-threaded interpreters. ## Example: Toyglk A basic demo Glk implementation, using crossterm as terminal backend. It hosts the Glulxe interpreter using the `glulxe` crate. - Aims to be a complete implementation of the Glk standard, including the Unicode extension. - Only supports one window: the entire terminal. - Line and character (also special keycodes) input. - Saving and restoring works. - Supports Glk styling and GarGlkText RGB colors. Several of my favorites stories like *Blue Lacuna* and *Counterfeit Monkey* work. e.g. ``` $ cargo run --release --example toyglk CounterfeitMonkey.gblorb ... Can you hear me? >> yes Good, you're conscious. We're conscious. I've heard urban legends about synthesis going wrong, one half person getting lost. ``` ![Counterfeit Monkey](/screenshots/cm.png) ![Glk+GarGlk styles](/screenshots/styles.png) ## Glk types `glui32` is directly mapped to `u32`, and `glsi32` to `i32`. The opaque handle types (`frefid_t`, `schanid_t`, `strid_t`, `winid_t`) are represented as opaque types that can be cast from and to `usize` (or a pointer, if you're living dangerously). Struct types `event_t`, `glkdate_t`, `glktimeval_t`, `stream_result_t` are provided as C-compatible structs. Convenience types have been defined for gestalts, event types, keycodes and such. These are newtypes that wrap a `u32`, not enums, to leave room for extensions (or ad-hoc need) to pass new values. ## License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. (note that the inner crate, `glk-sys` is licensed under a MIT license only, because it is based on files from glk which are licensed such) ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.