rust: more tests, refactors & improvements
- add ncplane_putchar_yx & ncplane_putchar static functions - complete test for channel_default_p - add more tests for ncplane - separate tests and constructors into submodules for ncplane and notcurses - make public FILE_NC & FILE_LIBC - improve integration tests. - clean & rustfmt - add constant NCRESULT_OK, NCRESULT_ERR and use them to refer to the NcResult values when appropriatepull/1166/head
parent
a4e7513b11
commit
e2ec27d413
@ -1,381 +0,0 @@
|
||||
// functions already exported by bindgen : 36
|
||||
// ------------------------------------------
|
||||
// notcurses_at_yx
|
||||
// notcurses_bottom
|
||||
//# notcurses_canchangecolor
|
||||
//# notcurses_canfade
|
||||
//# notcurses_canopen_images
|
||||
//# notcurses_canopen_videos
|
||||
//# notcurses_cansixel
|
||||
//# notcurses_cantruecolor
|
||||
//# notcurses_canutf8
|
||||
// notcurses_cursor_disable
|
||||
// notcurses_cursor_enable
|
||||
//# notcurses_debug
|
||||
// notcurses_drop_planes
|
||||
// notcurses_getc
|
||||
//# notcurses_init
|
||||
// notcurses_inputready_fd
|
||||
// notcurses_lex_blitter
|
||||
// notcurses_lex_margins
|
||||
// notcurses_lex_scalemode
|
||||
// notcurses_mouse_disable
|
||||
// notcurses_mouse_enable
|
||||
// notcurses_palette_size
|
||||
// notcurses_refresh
|
||||
// notcurses_render
|
||||
// notcurses_render_to_buffer
|
||||
// notcurses_render_to_file
|
||||
// notcurses_stats
|
||||
// notcurses_stats_alloc
|
||||
// notcurses_stats_reset
|
||||
// notcurses_stdplane
|
||||
// notcurses_stdplane_const
|
||||
//# notcurses_stop
|
||||
// notcurses_str_blitter
|
||||
// notcurses_str_scalemode
|
||||
// notcurses_supported_styles
|
||||
// notcurses_top
|
||||
// notcurses_ucs32_to_utf8
|
||||
// notcurses_version
|
||||
// notcurses_version_components
|
||||
//
|
||||
// static inline functions total: 6
|
||||
// ----------------------------------------- (done / remaining)
|
||||
// (+) implement : 5 / 1
|
||||
// (#) unit tests: 0 / 6
|
||||
// -----------------------------------------
|
||||
//+ notcurses_align
|
||||
//+ notcurses_getc_blocking
|
||||
//+ notcurses_getc_nblock
|
||||
//+ notcurses_stddim_yx
|
||||
//+ notcurses_stddim_yx_const
|
||||
//+ notcurses_term_dim_yx
|
||||
|
||||
use core::ptr::{null, null_mut};
|
||||
|
||||
use crate::{
|
||||
// NOTE: can't use libc::timespec nor libc::sigset_t
|
||||
// with notcurses_getc(()
|
||||
bindings::{sigemptyset, sigfillset, sigset_t, timespec},
|
||||
ncplane_dim_yx, notcurses_getc, notcurses_init, notcurses_stdplane, notcurses_stdplane_const,
|
||||
types::{
|
||||
NcAlign, NcInput, NcLogLevel, NcPlane, Notcurses, NotcursesOptions, NCALIGN_CENTER,
|
||||
NCALIGN_LEFT, NCOPTION_NO_ALTERNATE_SCREEN, NCOPTION_SUPPRESS_BANNERS,
|
||||
},
|
||||
};
|
||||
|
||||
impl NotcursesOptions {
|
||||
/// Simple `NotcursesOptions` constructor
|
||||
pub fn new() -> Self {
|
||||
Self::with_all_options(0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with customizable margins
|
||||
pub fn with_margins(top: i32, right: i32, bottom: i32, left: i32) -> Self {
|
||||
Self::with_all_options(0, top, right, bottom, left, 0)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with customizable flags
|
||||
pub fn with_flags(flags: u64) -> Self {
|
||||
Self::with_all_options(0, 0, 0, 0, 0, flags)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with all the options available
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// - loglevel
|
||||
///
|
||||
/// Progressively higher log levels result in more logging to stderr. By
|
||||
/// default, nothing is printed to stderr once fullscreen service begins.
|
||||
///
|
||||
/// - margin_t, margin_r, margin_b, margin_l
|
||||
///
|
||||
/// Desirable margins (top, right, bottom, left).
|
||||
///
|
||||
/// If all are 0 (default), we will render to the entirety of the screen.
|
||||
/// If the screen is too small, we do what we can.
|
||||
/// Absolute coordinates are relative to the rendering area
|
||||
/// ((0, 0) is always the origin of the rendering area).
|
||||
///
|
||||
/// - flags
|
||||
///
|
||||
/// General flags; This is expressed as a bitfield so that future options
|
||||
/// can be added without reshaping the struct.
|
||||
/// Undefined bits must be set to 0.
|
||||
///
|
||||
/// - [`NCOPTION_INHIBIT_SETLOCALE`]
|
||||
/// - [`NCOPTION_NO_ALTERNATE_SCREEN`]
|
||||
/// - [`NCOPTION_NO_FONT_CHANGES`]
|
||||
/// - [`NCOPTION_NO_QUIT_SIGHANDLERS`]
|
||||
/// - [`NCOPTION_NO_WINCH_SIGHANDLER`]
|
||||
/// - [`NCOPTION_SUPPRESS_BANNERS`]
|
||||
///
|
||||
pub fn with_all_options(
|
||||
loglevel: NcLogLevel,
|
||||
margin_t: i32,
|
||||
margin_r: i32,
|
||||
margin_b: i32,
|
||||
margin_l: i32,
|
||||
flags: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
termtype: null(),
|
||||
renderfp: null_mut(),
|
||||
loglevel,
|
||||
margin_t,
|
||||
margin_r,
|
||||
margin_b,
|
||||
margin_l,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Notcurses {
|
||||
/// `Notcurses` simple constructor with clean output
|
||||
pub unsafe fn new<'a>() -> &'a mut Notcurses {
|
||||
let options = NotcursesOptions::with_flags(NCOPTION_SUPPRESS_BANNERS);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor, showing banners
|
||||
pub unsafe fn with_banners<'a>() -> &'a mut Notcurses {
|
||||
&mut *notcurses_init(&NotcursesOptions::new(), null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor without an alternate screen
|
||||
pub unsafe fn without_altscreen<'a>() -> &'a mut Notcurses {
|
||||
let options = NotcursesOptions::with_flags(NCOPTION_NO_ALTERNATE_SCREEN);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor without an alternate screen
|
||||
pub unsafe fn without_altscreen_nor_banners<'a>() -> &'a mut Notcurses {
|
||||
let options =
|
||||
NotcursesOptions::with_flags(NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_SUPPRESS_BANNERS);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` constructor with options
|
||||
pub unsafe fn with_options<'a>(options: &NotcursesOptions) -> &'a mut Notcurses {
|
||||
&mut *notcurses_init(options, null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// return the offset into 'availcols' at which 'cols' ought be output given the requirements of 'align'
|
||||
#[inline]
|
||||
pub fn notcurses_align(availcols: i32, align: NcAlign, cols: i32) -> i32 {
|
||||
if align == NCALIGN_LEFT {
|
||||
return 0;
|
||||
}
|
||||
if cols > availcols {
|
||||
return 0;
|
||||
}
|
||||
if align == NCALIGN_CENTER {
|
||||
return (availcols - cols) / 2;
|
||||
}
|
||||
availcols - cols // NCALIGN_RIGHT
|
||||
}
|
||||
|
||||
/// 'input' may be NULL if the caller is uninterested in event details.
|
||||
/// If no event is ready, returns 0.
|
||||
// TODO: use pakr-signals
|
||||
#[inline]
|
||||
pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char {
|
||||
unsafe {
|
||||
let mut sigmask = sigset_t { __val: [0; 16] };
|
||||
sigfillset(&mut sigmask);
|
||||
let ts = timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
core::char::from_u32_unchecked(notcurses_getc(nc, &ts, &mut sigmask, input))
|
||||
}
|
||||
}
|
||||
|
||||
/// 'input' may be NULL if the caller is uninterested in event details.
|
||||
/// Blocks until an event is processed or a signal is received.
|
||||
#[inline]
|
||||
pub fn notcurses_getc_nblocking(nc: &mut Notcurses, input: &mut NcInput) -> char {
|
||||
unsafe {
|
||||
let mut sigmask = sigset_t { __val: [0; 16] };
|
||||
sigemptyset(&mut sigmask);
|
||||
core::char::from_u32_unchecked(notcurses_getc(nc, null(), &mut sigmask, input))
|
||||
}
|
||||
}
|
||||
|
||||
/// notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
|
||||
#[inline]
|
||||
pub fn notcurses_stddim_yx(nc: &mut Notcurses, y: &mut i32, x: &mut i32) -> NcPlane {
|
||||
unsafe {
|
||||
let s = notcurses_stdplane(nc);
|
||||
ncplane_dim_yx(s, y, x);
|
||||
*s
|
||||
}
|
||||
}
|
||||
|
||||
/// notcurses_stdplane_const(), plus free bonus dimensions written to non-NULL y/x!
|
||||
#[inline]
|
||||
pub fn notcurses_stddim_yx_const(nc: &Notcurses, y: &mut i32, x: &mut i32) -> NcPlane {
|
||||
unsafe {
|
||||
let s = notcurses_stdplane_const(nc);
|
||||
ncplane_dim_yx(s, y, x);
|
||||
*s
|
||||
}
|
||||
}
|
||||
|
||||
/// Return our current idea of the terminal dimensions in rows and cols.
|
||||
#[inline]
|
||||
pub fn notcurses_term_dim_yx(nc: &Notcurses, rows: &mut u32, cols: &mut u32) {
|
||||
unsafe {
|
||||
let mut irows = *rows as i32;
|
||||
let mut icols = *cols as i32;
|
||||
ncplane_dim_yx(
|
||||
notcurses_stdplane_const(nc), &mut irows, &mut icols);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serial_test::serial;
|
||||
|
||||
use std::io::Read;
|
||||
|
||||
use crate::{notcurses_stop, NcFile, Notcurses};
|
||||
|
||||
/*
|
||||
#[test]
|
||||
#[serial]
|
||||
fn () {
|
||||
}
|
||||
*/
|
||||
|
||||
// Test the bindgen functions ----------------------------------------------
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_init() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
assert![nc as *mut _ != core::ptr::null_mut()];
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
// FIXME: always return null
|
||||
fn notcurses_at_yx() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let mut sm = 0;
|
||||
let mut ch = 0;
|
||||
let res = crate::notcurses_at_yx(nc, 0, 0, &mut sm, &mut ch);
|
||||
notcurses_stop(nc);
|
||||
assert![!res.is_null()];
|
||||
|
||||
//print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_debug() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let mut _p: *mut i8 = &mut 0;
|
||||
let mut _size: *mut usize = &mut 0;
|
||||
let mut file = NcFile::from_libc(libc::open_memstream(&mut _p, _size));
|
||||
crate::notcurses_debug(nc, file.as_nc_ptr());
|
||||
notcurses_stop(nc);
|
||||
|
||||
let mut string1 = String::new();
|
||||
let _result = file.read_to_string(&mut string1);
|
||||
|
||||
let string2 =
|
||||
" ************************** notcurses debug state *****************************";
|
||||
|
||||
assert_eq![&string1[0..string2.len()], &string2[..]];
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canchangecolor() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canchangecolor(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canfade() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canfade(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canopen_images() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canopen_images(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canopen_videos() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canopen_videos(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_cansixel() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_cansixel(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_cantruecolor() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_cantruecolor(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canutf8() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canutf8(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
//! Handy [`Notcurses`] and [`NotcursesOptions`] constructors
|
||||
|
||||
use core::ptr::{null, null_mut};
|
||||
|
||||
use crate::{
|
||||
notcurses_init, NcLogLevel, Notcurses, NotcursesOptions, NCOPTION_NO_ALTERNATE_SCREEN,
|
||||
NCOPTION_SUPPRESS_BANNERS,
|
||||
};
|
||||
|
||||
impl NotcursesOptions {
|
||||
/// Simple `NotcursesOptions` constructor
|
||||
pub fn new() -> Self {
|
||||
Self::with_all_options(0, 0, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with customizable margins
|
||||
pub fn with_margins(top: i32, right: i32, bottom: i32, left: i32) -> Self {
|
||||
Self::with_all_options(0, top, right, bottom, left, 0)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with customizable flags
|
||||
pub fn with_flags(flags: u64) -> Self {
|
||||
Self::with_all_options(0, 0, 0, 0, 0, flags)
|
||||
}
|
||||
|
||||
/// `NotcursesOptions` constructor with all the options available
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// - loglevel
|
||||
///
|
||||
/// Progressively higher log levels result in more logging to stderr. By
|
||||
/// default, nothing is printed to stderr once fullscreen service begins.
|
||||
///
|
||||
/// - margin_t, margin_r, margin_b, margin_l
|
||||
///
|
||||
/// Desirable margins (top, right, bottom, left).
|
||||
///
|
||||
/// If all are 0 (default), we will render to the entirety of the screen.
|
||||
/// If the screen is too small, we do what we can.
|
||||
/// Absolute coordinates are relative to the rendering area
|
||||
/// ((0, 0) is always the origin of the rendering area).
|
||||
///
|
||||
/// - flags
|
||||
///
|
||||
/// General flags; This is expressed as a bitfield so that future options
|
||||
/// can be added without reshaping the struct.
|
||||
/// Undefined bits must be set to 0.
|
||||
///
|
||||
/// - [`NCOPTION_INHIBIT_SETLOCALE`]
|
||||
/// - [`NCOPTION_NO_ALTERNATE_SCREEN`]
|
||||
/// - [`NCOPTION_NO_FONT_CHANGES`]
|
||||
/// - [`NCOPTION_NO_QUIT_SIGHANDLERS`]
|
||||
/// - [`NCOPTION_NO_WINCH_SIGHANDLER`]
|
||||
/// - [`NCOPTION_SUPPRESS_BANNERS`]
|
||||
///
|
||||
pub fn with_all_options(
|
||||
loglevel: NcLogLevel,
|
||||
margin_t: i32,
|
||||
margin_r: i32,
|
||||
margin_b: i32,
|
||||
margin_l: i32,
|
||||
flags: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
termtype: null(),
|
||||
renderfp: null_mut(),
|
||||
loglevel,
|
||||
margin_t,
|
||||
margin_r,
|
||||
margin_b,
|
||||
margin_l,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Notcurses {
|
||||
/// `Notcurses` simple constructor with clean output
|
||||
pub unsafe fn new<'a>() -> &'a mut Notcurses {
|
||||
let options = NotcursesOptions::with_flags(NCOPTION_SUPPRESS_BANNERS);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor, showing banners
|
||||
pub unsafe fn with_banners<'a>() -> &'a mut Notcurses {
|
||||
&mut *notcurses_init(&NotcursesOptions::new(), null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor without an alternate screen
|
||||
pub unsafe fn without_altscreen<'a>() -> &'a mut Notcurses {
|
||||
let options = NotcursesOptions::with_flags(NCOPTION_NO_ALTERNATE_SCREEN);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` simple constructor without an alternate screen
|
||||
pub unsafe fn without_altscreen_nor_banners<'a>() -> &'a mut Notcurses {
|
||||
let options =
|
||||
NotcursesOptions::with_flags(NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_SUPPRESS_BANNERS);
|
||||
&mut *notcurses_init(&options, null_mut())
|
||||
}
|
||||
|
||||
/// `Notcurses` constructor with options
|
||||
pub unsafe fn with_options<'a>(options: &NotcursesOptions) -> &'a mut Notcurses {
|
||||
&mut *notcurses_init(options, null_mut())
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
// functions already exported by bindgen : 39
|
||||
// ----------------------------------------- (done / remaining)
|
||||
// (#) unit tests: 10 / 29
|
||||
// ------------------------------------------
|
||||
// notcurses_at_yx
|
||||
// notcurses_bottom
|
||||
//# notcurses_canchangecolor
|
||||
//# notcurses_canfade
|
||||
//# notcurses_canopen_images
|
||||
//# notcurses_canopen_videos
|
||||
//# notcurses_cansixel
|
||||
//# notcurses_cantruecolor
|
||||
//# notcurses_canutf8
|
||||
// notcurses_cursor_disable
|
||||
// notcurses_cursor_enable
|
||||
//# notcurses_debug
|
||||
// notcurses_drop_planes
|
||||
// notcurses_getc
|
||||
//# notcurses_init
|
||||
// notcurses_inputready_fd
|
||||
// notcurses_lex_blitter
|
||||
// notcurses_lex_margins
|
||||
// notcurses_lex_scalemode
|
||||
// notcurses_mouse_disable
|
||||
// notcurses_mouse_enable
|
||||
// notcurses_palette_size
|
||||
// notcurses_refresh
|
||||
// notcurses_render
|
||||
// notcurses_render_to_buffer
|
||||
// notcurses_render_to_file
|
||||
// notcurses_stats
|
||||
// notcurses_stats_alloc
|
||||
// notcurses_stats_reset
|
||||
// notcurses_stdplane
|
||||
// notcurses_stdplane_const
|
||||
//# notcurses_stop
|
||||
// notcurses_str_blitter
|
||||
// notcurses_str_scalemode
|
||||
// notcurses_supported_styles
|
||||
// notcurses_top
|
||||
// notcurses_ucs32_to_utf8
|
||||
// notcurses_version
|
||||
// notcurses_version_components
|
||||
//
|
||||
// static inline functions total: 6
|
||||
// ----------------------------------------- (done / remaining)
|
||||
// (+) implement : 6 / 0
|
||||
// (#) unit tests: 0 / 6
|
||||
// -----------------------------------------
|
||||
//+ notcurses_align
|
||||
//+ notcurses_getc_blocking
|
||||
//+ notcurses_getc_nblock
|
||||
//+ notcurses_stddim_yx
|
||||
//+ notcurses_stddim_yx_const
|
||||
//+ notcurses_term_dim_yx
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
mod constructors;
|
||||
pub use constructors::*;
|
||||
|
||||
use core::ptr::null;
|
||||
|
||||
use crate::{
|
||||
// NOTE: can't use libc::timespec nor libc::sigset_t
|
||||
// with notcurses_getc(()
|
||||
bindings::{sigemptyset, sigfillset, sigset_t, timespec},
|
||||
ncplane_dim_yx,
|
||||
notcurses_getc,
|
||||
notcurses_stdplane,
|
||||
notcurses_stdplane_const,
|
||||
types::{NcAlign, NcInput, NcPlane, Notcurses, NCALIGN_CENTER, NCALIGN_LEFT},
|
||||
};
|
||||
|
||||
/// return the offset into 'availcols' at which 'cols' ought be output given the requirements of 'align'
|
||||
#[inline]
|
||||
pub fn notcurses_align(availcols: i32, align: NcAlign, cols: i32) -> i32 {
|
||||
if align == NCALIGN_LEFT {
|
||||
return 0;
|
||||
}
|
||||
if cols > availcols {
|
||||
return 0;
|
||||
}
|
||||
if align == NCALIGN_CENTER {
|
||||
return (availcols - cols) / 2;
|
||||
}
|
||||
availcols - cols // NCALIGN_RIGHT
|
||||
}
|
||||
|
||||
/// 'input' may be NULL if the caller is uninterested in event details.
|
||||
/// If no event is ready, returns 0.
|
||||
// TODO: use pakr-signals
|
||||
#[inline]
|
||||
pub fn notcurses_getc_nblock(nc: &mut Notcurses, input: &mut NcInput) -> char {
|
||||
unsafe {
|
||||
let mut sigmask = sigset_t { __val: [0; 16] };
|
||||
sigfillset(&mut sigmask);
|
||||
let ts = timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
core::char::from_u32_unchecked(notcurses_getc(nc, &ts, &mut sigmask, input))
|
||||
}
|
||||
}
|
||||
|
||||
/// 'input' may be NULL if the caller is uninterested in event details.
|
||||
/// Blocks until an event is processed or a signal is received.
|
||||
#[inline]
|
||||
pub fn notcurses_getc_nblocking(nc: &mut Notcurses, input: &mut NcInput) -> char {
|
||||
unsafe {
|
||||
let mut sigmask = sigset_t { __val: [0; 16] };
|
||||
sigemptyset(&mut sigmask);
|
||||
core::char::from_u32_unchecked(notcurses_getc(nc, null(), &mut sigmask, input))
|
||||
}
|
||||
}
|
||||
|
||||
/// notcurses_stdplane(), plus free bonus dimensions written to non-NULL y/x!
|
||||
#[inline]
|
||||
pub fn notcurses_stddim_yx(nc: &mut Notcurses, y: &mut i32, x: &mut i32) -> NcPlane {
|
||||
unsafe {
|
||||
let s = notcurses_stdplane(nc);
|
||||
ncplane_dim_yx(s, y, x);
|
||||
*s
|
||||
}
|
||||
}
|
||||
|
||||
/// notcurses_stdplane_const(), plus free bonus dimensions written to non-NULL y/x!
|
||||
#[inline]
|
||||
pub fn notcurses_stddim_yx_const(nc: &Notcurses, y: &mut i32, x: &mut i32) -> NcPlane {
|
||||
unsafe {
|
||||
let s = notcurses_stdplane_const(nc);
|
||||
ncplane_dim_yx(s, y, x);
|
||||
*s
|
||||
}
|
||||
}
|
||||
|
||||
/// Return our current idea of the terminal dimensions in rows and cols.
|
||||
#[inline]
|
||||
pub fn notcurses_term_dim_yx(nc: &Notcurses, rows: &mut u32, cols: &mut u32) {
|
||||
unsafe {
|
||||
let mut irows = *rows as i32;
|
||||
let mut icols = *cols as i32;
|
||||
ncplane_dim_yx(notcurses_stdplane_const(nc), &mut irows, &mut icols);
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
//! [`Notcurses`] tests
|
||||
|
||||
use serial_test::serial;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::{notcurses_stop, NcFile, Notcurses};
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canchangecolor() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canchangecolor(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canfade() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canfade(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canopen_images() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canopen_images(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canopen_videos() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canopen_videos(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_cansixel() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_cansixel(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_cantruecolor() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_cantruecolor(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_canutf8() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let res = crate::notcurses_canutf8(nc);
|
||||
notcurses_stop(nc);
|
||||
print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_init() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
assert![nc as *mut _ != core::ptr::null_mut()];
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
// FIXME: always return null
|
||||
fn notcurses_at_yx() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let mut sm = 0;
|
||||
let mut ch = 0;
|
||||
let res = crate::notcurses_at_yx(nc, 0, 0, &mut sm, &mut ch);
|
||||
notcurses_stop(nc);
|
||||
assert![!res.is_null()];
|
||||
|
||||
//print!("[{}] ", res);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn notcurses_debug() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let mut _p: *mut i8 = &mut 0;
|
||||
let mut _size: *mut usize = &mut 0;
|
||||
let mut file = NcFile::from_libc(libc::open_memstream(&mut _p, _size));
|
||||
crate::notcurses_debug(nc, file.as_nc_ptr());
|
||||
notcurses_stop(nc);
|
||||
|
||||
let mut string1 = String::new();
|
||||
let _result = file.read_to_string(&mut string1);
|
||||
|
||||
let string2 =
|
||||
" ************************** notcurses debug state *****************************";
|
||||
|
||||
assert_eq![&string1[0..string2.len()], &string2[..]];
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
//! Handy [`NcPlane`] and [`NcPlaneOptions`] constructors
|
||||
|
||||
use core::ptr::{null, null_mut};
|
||||
|
||||
use crate::{
|
||||
ncpile_create, ncplane_create, notcurses_term_dim_yx, NcAlign, NcPlane, NcPlaneOptions,
|
||||
Notcurses, NCPLANE_OPTION_HORALIGNED,
|
||||
};
|
||||
|
||||
impl NcPlaneOptions {
|
||||
/// [`NcPlaneOptions`] simple constructor with horizontal x
|
||||
pub fn new(y: i32, x: i32, rows: u32, cols: u32) -> Self {
|
||||
Self::with_flags(y, x, rows, cols, 0)
|
||||
}
|
||||
|
||||
/// [`NcPlaneOptions`] simple constructor with horizontal alignment
|
||||
pub fn new_halign(y: i32, align: NcAlign, rows: u32, cols: u32) -> Self {
|
||||
Self::with_flags(y, align as i32, rows, cols, NCPLANE_OPTION_HORALIGNED)
|
||||
}
|
||||
|
||||
/// [`NcPlaneOptions`] constructor
|
||||
///
|
||||
/// Note: If you use`NCPLANE_OPTION_HORALIGNED` flag, you must provide
|
||||
/// the `NcAlign` value as the `x` parameter, casted to `i32`.
|
||||
pub fn with_flags(y: i32, x: i32, rows: u32, cols: u32, flags: u64) -> Self {
|
||||
NcPlaneOptions {
|
||||
y,
|
||||
x,
|
||||
rows: rows as i32,
|
||||
cols: cols as i32,
|
||||
userptr: null_mut(),
|
||||
name: null(),
|
||||
resizecb: None,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NcPlane {
|
||||
/// [`NcPlane`] constructor
|
||||
///
|
||||
/// The returned plane will be the top, bottom, and root of this new pile.
|
||||
pub unsafe fn new<'a>(
|
||||
nc: &mut Notcurses,
|
||||
y: i32,
|
||||
x: i32,
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
) -> &'a mut NcPlane {
|
||||
let options = NcPlaneOptions::new(y, x, rows, cols);
|
||||
&mut *ncpile_create(nc, &options)
|
||||
}
|
||||
|
||||
/// [`NcPlane`] constructor, expecting an [`NcPlaneOptions`] struct
|
||||
///
|
||||
/// The returned plane will be the top, bottom, and root of this new pile.
|
||||
pub unsafe fn with_options<'a>(
|
||||
nc: &mut Notcurses,
|
||||
options: &NcPlaneOptions,
|
||||
) -> &'a mut NcPlane {
|
||||
&mut *ncpile_create(nc, options)
|
||||
}
|
||||
|
||||
/// [`NcPlane`] constructor, bound to another plane
|
||||
pub unsafe fn new_bound<'a>(
|
||||
bound_to: &mut NcPlane,
|
||||
y: i32,
|
||||
x: i32,
|
||||
rows: u32,
|
||||
cols: u32,
|
||||
) -> &'a mut NcPlane {
|
||||
let options = NcPlaneOptions::new(y, x, rows, cols);
|
||||
&mut *ncplane_create(bound_to, &options)
|
||||
}
|
||||
|
||||
/// [`NcPlane`] constructor, bound to another plane,
|
||||
/// expecting an [`NcPlaneOptions`] struct
|
||||
///
|
||||
/// The returned plane will be the top, bottom, and root of this new pile.
|
||||
pub unsafe fn with_options_bound<'a>(
|
||||
nc: &mut Notcurses,
|
||||
options: &NcPlaneOptions,
|
||||
) -> &'a mut NcPlane {
|
||||
&mut *ncpile_create(nc, options)
|
||||
}
|
||||
|
||||
/// [`NcPlane`] constructor, with the same dimensions of the terminal.
|
||||
///
|
||||
/// The returned plane will be the top, bottom, and root of this new pile.
|
||||
// FIXME BUG
|
||||
pub unsafe fn new_termsize<'a>(nc: &mut Notcurses) -> &'a mut NcPlane {
|
||||
let (mut trows, mut tcols) = (0, 0);
|
||||
notcurses_term_dim_yx(nc, &mut trows, &mut tcols);
|
||||
assert![(trows > 0) & (tcols > 0)];
|
||||
&mut *ncpile_create(nc, &NcPlaneOptions::new(0, 0, trows as u32, tcols as u32))
|
||||
}
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
//! [`NcPlane`] tests
|
||||
|
||||
use crate::{notcurses_stop, NcPlane, NcPlaneOptions, Notcurses, NCRESULT_OK};
|
||||
use serial_test::serial;
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_options() {
|
||||
let _po = NcPlaneOptions::new(0, 0, 20, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncpile_create() {
|
||||
let po = NcPlaneOptions::new(0, 0, 20, 20);
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let _p = NcPlane::with_options(nc, &po);
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_notcurses() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
let nc2 = crate::ncplane_notcurses(plane);
|
||||
assert_eq![nc as *mut _, nc2];
|
||||
|
||||
let nc3 = crate::ncplane_notcurses_const(plane);
|
||||
assert_eq![nc as *const _, nc3];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_cursor() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
let (mut y, mut x) = (0, 0);
|
||||
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
|
||||
assert_eq![x, 0];
|
||||
assert_eq![y, 0];
|
||||
|
||||
let res = crate::ncplane_cursor_move_yx(plane, 10, 15);
|
||||
assert_eq![res, 0];
|
||||
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
|
||||
assert_eq![x, 15];
|
||||
assert_eq![y, 10];
|
||||
|
||||
crate::ncplane_home(plane);
|
||||
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
|
||||
assert_eq![x, 0];
|
||||
assert_eq![y, 0];
|
||||
|
||||
let _res = crate::ncplane_cursor_move_yx(plane, 10, 15);
|
||||
crate::ncplane_erase(plane); // has to move the cursor to 0,0
|
||||
crate::ncplane_cursor_yx(plane, &mut y, &mut x);
|
||||
assert_eq![x, 0];
|
||||
assert_eq![y, 0];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_channels() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
let channels = crate::ncplane_channels(plane);
|
||||
assert_eq![channels, 0];
|
||||
|
||||
crate::ncplane_set_channels(plane, 0x1122334455667788);
|
||||
assert_eq![0x1122334455667788, crate::ncplane_channels(plane)];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_fchannel() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
crate::ncplane_set_channels(plane, 0x1122334455667788);
|
||||
let channels = crate::ncplane_channels(plane);
|
||||
assert_eq![0x11223344, crate::channels_fchannel(channels)];
|
||||
|
||||
let channels = crate::ncplane_set_fchannel(plane, 0x10203040);
|
||||
assert_eq![0x10203040, crate::channels_fchannel(channels)];
|
||||
assert_eq![0x1020304055667788, channels];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_bchannel() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
crate::ncplane_set_channels(plane, 0x1122334455667788);
|
||||
let channels = crate::ncplane_channels(plane);
|
||||
assert_eq![0x55667788, crate::channels_bchannel(channels)];
|
||||
|
||||
// BUG? ncplane_set_bchannel and ncplane_set_fchannel don't get
|
||||
// applied unless they are assigned to a variable. Weird.
|
||||
|
||||
let channels = crate::ncplane_set_bchannel(plane, 0x50607080);
|
||||
assert_eq![0x50607080, crate::channels_bchannel(channels)];
|
||||
assert_eq![0x1122334450607080, channels];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_rgb() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
crate::ncplane_set_fg_rgb(plane, 0x112233);
|
||||
assert_eq![0x112233, crate::ncplane_fg_rgb(plane)];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_default() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
assert_eq![true, crate::ncplane_bg_default_p(plane)];
|
||||
assert_eq![true, crate::ncplane_fg_default_p(plane)];
|
||||
|
||||
crate::ncplane_set_bg_rgb8(plane, 11, 22, 33);
|
||||
crate::ncplane_set_fg_rgb8(plane, 44, 55, 66);
|
||||
assert_eq![false, crate::ncplane_bg_default_p(plane)];
|
||||
assert_eq![false, crate::ncplane_fg_default_p(plane)];
|
||||
|
||||
crate::ncplane_set_bg_default(plane);
|
||||
crate::ncplane_set_fg_default(plane);
|
||||
assert_eq![true, crate::ncplane_bg_default_p(plane)];
|
||||
assert_eq![true, crate::ncplane_fg_default_p(plane)];
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_dimensions() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 10, 20);
|
||||
|
||||
let (mut y, mut x) = (0, 0);
|
||||
crate::ncplane_dim_yx(plane, &mut y, &mut x);
|
||||
assert_eq!((10, 20), (y, x));
|
||||
|
||||
assert_eq!(10, crate::ncplane_dim_y(plane));
|
||||
assert_eq!(20, crate::ncplane_dim_x(plane));
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn ncplane_resize() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
let res = crate::ncplane_resize_simple(plane, 40, 40);
|
||||
assert_eq![NCRESULT_OK, res];
|
||||
|
||||
let (mut y, mut x) = (0, 0);
|
||||
crate::ncplane_dim_yx(plane, &mut y, &mut x);
|
||||
assert_eq!((40, 40), (y, x));
|
||||
|
||||
// TODO: test further plane subset keeping unchanged features
|
||||
let res = crate::ncplane_resize(plane, 0, 0, 0, 0, 0, 0, 60, 70);
|
||||
assert_eq![NCRESULT_OK, res];
|
||||
|
||||
assert_eq!(60, crate::ncplane_dim_y(plane));
|
||||
assert_eq!(70, crate::ncplane_dim_x(plane));
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: resizecb
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
// TODO: CHECK: zeroes out every cell of the plane, dumps the egcpool,
|
||||
// The base cell is preserved.
|
||||
fn ncplane_erase() {
|
||||
unsafe {
|
||||
let nc = Notcurses::new();
|
||||
let plane = NcPlane::new(nc, 0, 0, 20, 20);
|
||||
|
||||
crate::ncplane_set_bg_rgb(plane, 0x112233);
|
||||
crate::ncplane_set_fg_rgb(plane, 0x445566);
|
||||
assert_eq![false, crate::ncplane_bg_default_p(plane)];
|
||||
assert_eq![false, crate::ncplane_fg_default_p(plane)];
|
||||
|
||||
// FIXME? DEBUG
|
||||
crate::ncplane_erase(plane);
|
||||
// assert_eq![true, crate::ncplane_bg_default_p(plane)];
|
||||
// assert_eq![true, crate::ncplane_fg_default_p(plane)];
|
||||
//print!(" C: {:#0x} ", crate::ncplane_channels(plane));
|
||||
|
||||
notcurses_stop(nc);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue