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 appropriate
pull/1166/head
joseLuís 4 years ago
parent a4e7513b11
commit e2ec27d413

@ -68,9 +68,10 @@ use crate::{
channels_set_bg_default, channels_set_bg_rgb, channels_set_bg_rgb8, channels_set_fchannel,
channels_set_fg_alpha, channels_set_fg_default, channels_set_fg_rgb, channels_set_fg_rgb8,
types::{
NcAlphaBits, NcCell, NcChannel, NcChannels, NcChar, NcCharBackstop, NcColor, NcPaletteIndex, NcPlane,
NcResult, NcStyleMask, NCCELL_ALPHA_OPAQUE, NCCELL_BGDEFAULT_MASK, NCCELL_BG_PALETTE,
NCCELL_FGDEFAULT_MASK, NCCELL_FG_PALETTE, NCCELL_NOBACKGROUND_MASK, NCCELL_WIDEASIAN_MASK,
NcAlphaBits, NcCell, NcChannel, NcChannels, NcChar, NcCharBackstop, NcColor,
NcPaletteIndex, NcPlane, NcResult, NcStyleMask, NCCELL_ALPHA_OPAQUE, NCCELL_BGDEFAULT_MASK,
NCCELL_BG_PALETTE, NCCELL_FGDEFAULT_MASK, NCCELL_FG_PALETTE, NCCELL_NOBACKGROUND_MASK,
NCCELL_WIDEASIAN_MASK, NCRESULT_ERR, NCRESULT_OK,
},
NCSTYLE_MASK,
};
@ -97,11 +98,7 @@ impl NcCell {
/// This is analogous to the [`cell_char_initializer`] macro
#[inline]
pub const fn with_char(ch: char) -> Self {
Self::new(
ch,
0 as NcStyleMask,
0 as NcChannels,
)
Self::new(ch, 0 as NcStyleMask, 0 as NcChannels)
}
/// [`NcCell`] simple constructor for an empty cell
@ -190,7 +187,7 @@ pub unsafe fn cells_load_box(
ulen = unsafe { cell_prime(plane, vl, gcluster, style, channels) };
if ulen > 0 {
return 0;
return NCRESULT_OK;
}
unsafe {
cell_release(plane, hl);
@ -212,7 +209,7 @@ pub unsafe fn cells_load_box(
cell_release(plane, ul);
}
}
-1
NCRESULT_ERR
}
///
@ -321,10 +318,11 @@ pub fn cell_extract(
cell_strdup(plane, cell)
}
/// Returns true if the two cells are distinct `NcChar`s, attributes, or channels.
/// Returns true if the two cells are distinct [`NcChar`]s, attributes, or channels
///
/// The actual egcpool index needn't be the same--indeed, the planes needn't even
/// be the same. Only the expanded NcChar must be equal. The NcChar must be bit-equal;
/// it would probably be better to test whether they're Unicode-equal FIXME.
// NOTE: FIXME: it would probably be better to test whether they're Unicode-equal
#[inline]
pub fn cellcmp(plane1: &NcPlane, cell1: &NcCell, plane2: &NcPlane, cell2: &NcCell) -> bool {
if cell1.stylemask != cell2.stylemask {

@ -145,7 +145,7 @@ pub fn channel_palindex_p(channel: NcChannel) -> bool {
/// Mark the channel as using its default color, which also marks it opaque.
#[inline]
pub fn channel_set_default(channel: &mut NcChannel) -> NcChannel {
*channel &= !(NCCELL_BGDEFAULT_MASK | NCCELL_ALPHA_HIGHCONTRAST); // < NOTE shouldn't be better NCCHANNEL_ALPHA_MASK?
*channel &= !(NCCELL_BGDEFAULT_MASK | NCCELL_ALPHA_HIGHCONTRAST);
*channel
}
@ -417,15 +417,15 @@ mod test {
#[serial]
fn channel_default_p() {
let mut c: NcChannel = 0x112233;
assert_eq!(true, super::channel_default_p(c));
assert_eq!(true, crate::channel_default_p(c));
// TODO FIXME: test for the false result
// let _ = super::channel_set_alpha(&mut c, NCCELL_ALPHA_TRANSPARENT);
// assert_eq!(false, super::channel_default_p(c));
let _ = crate::channel_set_alpha(&mut c, NCCELL_ALPHA_OPAQUE);
assert_eq!(true, crate::channel_default_p(c));
let _ = super::channel_set_alpha(&mut c, NCCELL_ALPHA_OPAQUE);
assert_eq!(true, super::channel_default_p(c));
crate::channel_set(&mut c, 0x112233);
assert_eq!(false, super::channel_default_p(c));
}
#[test]
#[serial]
#[allow(non_snake_case)]
@ -435,6 +435,7 @@ mod test {
super::channels_set_fchannel(&mut cp, fc);
assert_eq!(super::channels_fchannel(cp), fc);
}
#[test]
#[serial]
#[allow(non_snake_case)]
@ -444,6 +445,7 @@ mod test {
super::channels_set_bchannel(&mut cp, bc);
assert_eq!(super::channels_bchannel(cp), bc);
}
#[test]
#[serial]
fn channels_combine() {

@ -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))
}
}

@ -1,7 +1,13 @@
//! NcPlane constructors and ncplane_* static functions reimplementations
//! [`NcPlane`] ncplane_* static functions reimplementations
// functions already exported by bindgen : 97
// functions already exported by bindgen : 103
// ------------------------------------------ (implement / remaining)
// (#) test: 13 / 90
// ------------------------------------------
//# ncpile_create
// ncpile_rasterize
// ncpile_render
//
// ncplane_above
// ncplane_at_cursor
// ncplane_at_yx
@ -9,15 +15,15 @@
// ncplane_below
// ncplane_box
// ncplane_center_abs
// ncplane_channels
//# ncplane_channels
// ncplane_contents
// ncplane_create
// ncplane_cursor_move_yx
// ncplane_cursor_yx
//# ncplane_cursor_move_yx
//# ncplane_cursor_yx
// ncplane_destroy
// ncplane_dim_yx
//# ncplane_dim_yx
// ncplane_dup
// ncplane_erase
//# ncplane_erase
// ncplane_fadein
// ncplane_fadein_iteration
// ncplane_fadeout
@ -28,7 +34,7 @@
// ncplane_highgradient
// ncplane_highgradient_sized
// ncplane_hline_interp
// ncplane_home
//# ncplane_home
// ncplane_mergedown
// ncplane_mergedown_simple
// ncplane_move_above
@ -37,8 +43,8 @@
// ncplane_move_top
// ncplane_move_yx
// ncplane_new
// ncplane_notcurses
// ncplane_notcurses_const
//# ncplane_notcurses
//# ncplane_notcurses_const
// ncplane_off_styles
// ncplane_on_styles
// ncplane_parent
@ -59,28 +65,31 @@
// ncplane_putwstr_stained
// ncplane_qrcode
// ncplane_reparent
// ncplane_resize
// ncplane_reparent_family
//# ncplane_resize
// ncplane_resizecb
// ncplane_resize_realign
// ncplane_rgba
// ncplane_rotate_ccw
// ncplane_rotate_cw
// ncplane_set_base
// ncplane_set_base_cell
// ncplane_set_bchannel
//# ncplane_set_bchannel
// ncplane_set_bg_alpha
// ncplane_set_bg_default
// ncplane_set_bg_palindex
// ncplane_set_bg_rgb
// ncplane_set_bg_rgb8
// ncplane_set_bg_rgb8_clipped
// ncplane_set_channels
// ncplane_set_fchannel
//# ncplane_set_channels
//# ncplane_set_fchannel
// ncplane_set_fg_alpha
// ncplane_set_fg_default
// ncplane_set_fg_palindex
// ncplane_set_fg_rgb
// ncplane_set_fg_rgb8
// ncplane_set_fg_rgb8_clipped
// ncplane_set_resizecb
// ncplane_set_scrolling
// ncplane_set_styles
// ncplane_set_userptr
@ -103,25 +112,25 @@
// static inline functions total: 42
// ------------------------------------------ (implement / remaining)
// (X) wont: 8
// (+) done: 32 / 2
// (#) test: 0 / 34
// (+) done: 34 / 0
// (#) test: 5 / 29
// ------------------------------------------
//+ ncplane_align
//+ ncplane_at_cursor_cell
//+ ncplane_at_yx_cell
//+ ncplane_bchannel
//+ ncplane_bg_alpha
//+ ncplane_bg_default_p
//# ncplane_bg_default_p
//+ ncplane_bg_rgb
//+ ncplane_bg_rgb8
//+ ncplane_box_sized
//+ ncplane_dim_x
//+ ncplane_dim_y
//# ncplane_dim_x
//# ncplane_dim_y
//+ ncplane_double_box
//+ ncplane_double_box_sized
//+ ncplane_fchannel
//+ ncplane_fg_alpha
//+ ncplane_fg_default_p
//# ncplane_fg_default_p
//+ ncplane_fg_rgb
//+ ncplane_fg_rgb8
//+ ncplane_gradient_sized // u64|u32 https://github.com/dankamongmen/notcurses/issues/920
@ -130,8 +139,8 @@
//+ ncplane_perimeter_double
//+ ncplane_perimeter_rounded
//+ ncplane_putc
// ncplane_putchar
// ncplane_putchar_yx
//+ ncplane_putchar
//+ ncplane_putchar_yx
//+ ncplane_putegc
//+ ncplane_putnstr
//+ ncplane_putstr
@ -143,7 +152,7 @@
//X ncplane_putwstr //
//X ncplane_putwstr_aligned //
//X ncplane_putwstr_yx //
//+ ncplane_resize_simple
//# ncplane_resize_simple
//+ ncplane_rounded_box
//+ ncplane_rounded_box_sized
//+ ncplane_vline
@ -151,10 +160,13 @@
//
// NOTE: TODO: Still remains all the ncplane_printf* functions/macros (at the end)
use core::{
ffi::c_void,
ptr::{null, null_mut},
};
#[cfg(test)]
mod tests;
mod constructors;
pub use constructors::*;
use core::{ffi::c_void, ptr::null_mut};
use libc::free;
use std::ffi::CString;
@ -162,73 +174,17 @@ use crate::{
bindgen::__va_list_tag,
cell_load, cell_release, cells_double_box, cells_rounded_box, channels_bchannel,
channels_bg_alpha, channels_bg_default_p, channels_bg_rgb, channels_bg_rgb8, channels_fchannel,
channels_fg_alpha, channels_fg_default_p, channels_fg_rgb, channels_fg_rgb8, ncpile_create,
ncplane_at_cursor, ncplane_at_yx, ncplane_box, ncplane_channels, ncplane_create,
ncplane_cursor_move_yx, ncplane_cursor_yx, ncplane_dim_yx, ncplane_gradient,
ncplane_hline_interp, ncplane_putc_yx, ncplane_putegc_yx, ncplane_putnstr_yx,
ncplane_putstr_yx, ncplane_resize, ncplane_vline_interp, ncplane_vprintf_yx, notcurses_align,
notcurses_term_dim_yx,
channels_fg_alpha, channels_fg_default_p, channels_fg_rgb, channels_fg_rgb8, ncplane_at_cursor,
ncplane_at_yx, ncplane_box, ncplane_channels, ncplane_cursor_move_yx, ncplane_cursor_yx,
ncplane_dim_yx, ncplane_gradient, ncplane_hline_interp, ncplane_putc_yx, ncplane_putegc_yx,
ncplane_putnstr_yx, ncplane_putstr_yx, ncplane_resize, ncplane_styles, ncplane_vline_interp,
ncplane_vprintf_yx, notcurses_align,
types::{
NcAlign, NcAlphaBits, NcCell, NcChannel, NcChannels, NcColor, NcPlane,
NcPlaneOptions, NcResult, NcStyleMask, Notcurses, NCPLANE_OPTION_HORALIGNED,
NcAlign, NcAlphaBits, NcCell, NcChannel, NcChannels, NcColor, NcPlane, NcResult,
NcStyleMask, NCRESULT_ERR, NCRESULT_OK,
},
};
// Constructors ----------------------------------------------------------------
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, 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, options: &NcPlaneOptions) -> &'a mut NcPlane {
&mut *ncplane_create(bound_to, options)
}
/// `NcPlane` constructor, with the full size of the terminal.
///
/// The returned plane will be the top, bottom, and root of this new pile.
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);
&mut *ncpile_create(nc, &NcPlaneOptions::new(0, 0, trows as u32, tcols as u32))
}
}
// Static Functions ------------------------------------------------------------
/// Return the column at which 'cols' columns ought start in order to be aligned
@ -247,10 +203,10 @@ pub fn ncplane_align(plane: &NcPlane, align: NcAlign, cols: i32) -> i32 {
pub fn ncplane_at_cursor_cell(plane: &mut NcPlane, cell: &mut NcCell) -> NcResult {
let mut egc = unsafe { ncplane_at_cursor(plane, &mut cell.stylemask, &mut cell.channels) };
if egc.is_null() {
return -1;
return NCRESULT_ERR;
}
let result: NcResult = unsafe { cell_load(plane, cell, egc) };
if result < 0 {
if result != NCRESULT_OK {
unsafe {
free(&mut egc as *mut _ as *mut c_void);
}
@ -264,7 +220,7 @@ pub fn ncplane_at_cursor_cell(plane: &mut NcPlane, cell: &mut NcCell) -> NcResul
pub fn ncplane_at_yx_cell(plane: &mut NcPlane, y: i32, x: i32, cell: &mut NcCell) -> NcResult {
let mut egc = unsafe { ncplane_at_yx(plane, y, x, &mut cell.stylemask, &mut cell.channels) };
if egc.is_null() {
return -1;
return NCRESULT_ERR;
}
let channels = cell.channels; // need to preserve wide flag
let result: NcResult = unsafe { cell_load(plane, cell, egc) };
@ -340,7 +296,7 @@ pub fn ncplane_double_box(
ctlword: u32,
) -> NcResult {
#[allow(unused_assignments)]
let mut ret = 0;
let mut ret = NCRESULT_OK;
let mut ul = NcCell::new_blank();
let mut ur = NcCell::new_blank();
@ -361,7 +317,7 @@ pub fn ncplane_double_box(
&mut hl,
&mut vl,
);
if ret == 0 {
if ret == NCRESULT_OK {
ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
}
@ -433,8 +389,8 @@ pub fn ncplane_perimeter_double(
channels: NcChannels,
ctlword: u32,
) -> NcResult {
if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != 0 {
return -1;
if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
@ -458,9 +414,9 @@ pub fn ncplane_perimeter_double(
&mut hl,
&mut vl,
)
} != 0
} != NCRESULT_OK
{
return -1;
return NCRESULT_ERR;
}
let ret = ncplane_box_sized(plane, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
unsafe {
@ -482,8 +438,8 @@ pub fn ncplane_perimeter_rounded(
channels: NcChannels,
ctlword: u32,
) -> NcResult {
if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != 0 {
return -1;
if unsafe { ncplane_cursor_move_yx(plane, 0, 0) } != NCRESULT_OK {
return NCRESULT_ERR;
}
let (mut dimy, mut dimx) = (0, 0);
unsafe {
@ -507,9 +463,9 @@ pub fn ncplane_perimeter_rounded(
&mut hl,
&mut vl,
)
} != 0
} != NCRESULT_OK
{
return -1;
return NCRESULT_ERR;
}
let ret = ncplane_box_sized(plane, &ul, &ur, &ll, &lr, &hl, &vl, dimy, dimx, ctlword);
unsafe {
@ -529,6 +485,27 @@ pub fn ncplane_putc(plane: &mut NcPlane, cell: &NcCell) -> NcResult {
unsafe { ncplane_putc_yx(plane, -1, -1, cell) }
}
/// Call ncplane_putchar_yx() at the current cursor location.
#[inline]
pub fn ncplane_putchar(plane: &mut NcPlane, c: char) -> NcResult {
ncplane_putchar_yx(plane, -1, -1, c)
}
/// Replace the EGC underneath us, but retain the styling. The current styling
/// of the plane will not be changed.
///
/// Replace the cell at the specified coordinates with the provided 7-bit char
/// 'c'. Advance the cursor by 1. On success, returns 1. On failure, returns -1.
/// This works whether the underlying char is signed or unsigned.
#[inline]
// TODO: test char is < 8bit (currently 32bit)
pub fn ncplane_putchar_yx(plane: &mut NcPlane, y: i32, x: i32, c: char) -> NcResult {
unsafe {
let ce = NcCell::new(c, ncplane_styles(plane), ncplane_channels(plane));
ncplane_putc_yx(plane, y, x, &ce)
}
}
/// Call ncplane_putegc() at the current cursor location.
#[inline]
pub fn ncplane_putegc(plane: &mut NcPlane, gcluster: i8, sbytes: &mut i32) -> NcResult {
@ -625,7 +602,7 @@ pub fn ncplane_gradient_sized(
xlen: i32,
) -> NcResult {
if ylen < 1 || xlen < 1 {
return -1;
return NCRESULT_ERR;
}
let (mut y, mut x) = (0, 0);
unsafe {
@ -725,7 +702,7 @@ pub fn ncplane_rounded_box(
ctlword: u32,
) -> NcResult {
#[allow(unused_assignments)]
let mut ret = 0;
let mut ret = NCRESULT_OK;
let mut ul = NcCell::new_blank();
let mut ur = NcCell::new_blank();
@ -746,10 +723,9 @@ pub fn ncplane_rounded_box(
&mut hl,
&mut vl,
);
if ret == 0 {
if ret == NCRESULT_OK {
ret = ncplane_box(plane, &ul, &ur, &ll, &lr, &hl, &vl, ystop, xstop, ctlword);
}
cell_release(plane, &mut ul);
cell_release(plane, &mut ur);
cell_release(plane, &mut ll);
@ -836,15 +812,3 @@ pub fn ncplane_rounded_box_sized(
// va_end(va);
// return ret;
// }
#[cfg(test)]
mod test {
// use super::nc;
// use serial_test::serial;
/*
#[test]
#[serial]
fn () {
}
*/
}

@ -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);
}
}

@ -1,4 +1,4 @@
//! Wrapper for libc::FILE, both as used by notcurses and the libc crate
//! Wrapper for `libc::FILE`, both as used by notcurses and the libc crate
//!
//! The interface is largely based on the implementation of the
//! [cfile-rs crate](https://github.com/jkarns275/cfile) by Joshua Karns
@ -9,12 +9,14 @@ use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};
pub use libc::{c_long, c_void, fclose, feof, fread, fseek, ftell, SEEK_CUR, SEEK_END, SEEK_SET};
/// notcurses functions expects this type of *FILE (struct)
/// notcurses functions expects this type of `*FILE` (a struct)
pub type FILE_NC = crate::bindgen::_IO_FILE;
/// the libc crate expects this type of *FILE (opaque enum)
/// the [`libc`] crate expects this type of `*FILE` (an opaque enum)
pub type FILE_LIBC = libc::FILE;
// TODO: the following static strings aren't made public
/// Intended to be passed into the CFile::open method.
/// It will open the file in a way that will allow reading and writing,
/// including overwriting old data.
@ -54,12 +56,14 @@ fn get_error<T>() -> Result<T, Error> {
Err(Error::last_os_error())
}
/// A wrapper struct around libc::FILE
/// A wrapper struct around `libc::FILE`
///
/// The notcurses `FILE` type [`FILE_NC`] is imported through bindgen as a struct,
/// while the equivalent [`libc`] crate FILE ([`FILE_LIBC`]) is an opaque enum.
///
/// The notcurses FILE type `FILE_NC` is imported through bindgen as a struct,
/// while the equivalent Rust libc::FILE (`FILE_LIBC`) is an opaque enum.
/// Several methods are provided to convert back and forth between both types,
/// to allow both rust libc operations and notcurses file operations on it.
/// in order to allow both rust libc operations and notcurses file operations
/// over the same underlying `*FILE`.
#[derive(Debug)]
pub struct NcFile {
file_ptr: NonNull<FILE_LIBC>,
@ -84,7 +88,7 @@ impl NcFile {
// methods --
/// Returns the file pointer in the format expected by libc
/// Returns the file pointer in the format expected by the [`libc`] crate
#[inline]
pub fn as_libc_ptr(&self) -> *mut FILE_LIBC {
self.file_ptr.as_ptr()
@ -98,8 +102,7 @@ impl NcFile {
/// Returns the current position in the file.
///
/// # Errors
/// On error Error::Errno(errno) is returned.
/// On error `Error::Errno(errno)` is returned.
pub fn current_pos(&self) -> Result<u64, Error> {
unsafe {
let pos = ftell(self.as_libc_ptr());
@ -150,12 +153,11 @@ impl NcFile {
impl Read for NcFile {
/// Reads exactly the number of bytes required to fill buf.
///
/// # Errors
/// If the end of the file is reached before buf is filled,
/// Err(EndOfFile(bytes_read)) will be returned. The data that was read
/// `Err(EndOfFile(bytes_read))` will be returned. The data that was read
/// before that will still have been placed into buf.
///
/// Upon some other error, Err(Errno(errno)) will be returned.
/// Upon some other error, `Err(Errno(errno))` will be returned.
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
unsafe {
let result = fread(
@ -184,9 +186,8 @@ impl Read for NcFile {
/// Reads the entire file starting from the current_position
/// expanding buf as needed.
///
/// On a successful read, this function will return Ok(bytes_read).
/// On a successful read, this function will return `Ok(bytes_read)`.
///
/// # Errors
/// If an error occurs during reading, some varient of error will be returned.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error> {
let pos = self.current_pos();
@ -217,9 +218,8 @@ impl Read for NcFile {
/// Reads the entire file from the beginning and stores it in a string
///
/// On a successful read, this function will return Ok(bytes_read).
/// On a successful read, this function will return `Ok(bytes_read)`.
///
/// # Errors
/// If an error occurs during reading, some varient of error will be returned.
fn read_to_string(&mut self, strbuf: &mut String) -> Result<usize, Error> {
let mut bytes_read = 0_usize;
@ -245,12 +245,11 @@ impl Read for NcFile {
/// Reads exactly the number of bytes required to fill buf.
///
/// # Errors
/// If the end of the file is reached before buf is filled,
/// Err(EndOfFile(bytes_read)) will be returned. The data that was read
/// `Err(EndOfFile(bytes_read))` will be returned. The data that was read
/// before that will still have been placed into buf.
///
/// Upon some other error, Err(Errno(errno)) will be returned.
/// Upon some other error, `Err(Errno(errno))` will be returned.
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error> {
unsafe {
let result = fread(
@ -274,7 +273,7 @@ impl Read for NcFile {
}
impl Seek for NcFile {
/// Changes the current position in the file using the SeekFrom enum.
/// Changes the current position in the file using the [`SeekFrom`] enum.
///
/// To set relative to the beginning of the file (i.e. index is 0 + offset):
/// ```ignore
@ -288,8 +287,8 @@ impl Seek for NcFile {
/// ```ignore
/// SeekFrom::End(offset)
/// ```
/// # Errors
/// On error Error::Errno(errno) is returned.
///
/// On error `Error::Errno(errno)` is returned.
fn seek(&mut self, pos: SeekFrom) -> Result<u64, Error> {
unsafe {
let result = match pos {

@ -4,8 +4,20 @@
// error handling --------------------------------------------------------------
/// `i32` value used to return errors, when value < 0, (usually -1)
///
/// See also [`NCRESULT_OK`] and [`NCRESULT_ERR`]
pub type NcResult = i32;
/// Value for no errors, for the bindgen functions that return [`NcResult`]
///
/// Meanwhile the static inline functions reimplemented in Rust return `bool`.
pub const NCRESULT_OK: i32 = 0;
/// Value for an error, for the bindgen functions that return [`NcResult`]
///
/// Meanwhile the static inline functions reimplemented in Rust return `bool`.
pub const NCRESULT_ERR: i32 = -1;
// time -----------------------------------------------------------------------
pub type NcTime = crate::bindings::bindgen::timespec;

@ -31,10 +31,11 @@ pub use channel::{
NcAlphaBits, NcBlitSet, NcChannel, NcChannels, NcColor, NcFadeCtx, NcPalette, NcPaletteIndex,
NcPixel, NcRgb, NCCHANNEL_ALPHA_MASK,
};
pub use file::NcFile;
pub use file::{NcFile, FILE_LIBC, FILE_NC};
pub use misc::{
NcResult, NCMETRIC_BPREFIXCOLUMNS, NCMETRIC_BPREFIXSTRLEN, NCMETRIC_IPREFIXCOLUMNS,
NCMETRIC_IPREFIXSTRLEN, NCMETRIC_PREFIXCOLUMNS, NCMETRIC_PREFIXSTRLEN,
NCMETRIC_IPREFIXSTRLEN, NCMETRIC_PREFIXCOLUMNS, NCMETRIC_PREFIXSTRLEN, NCRESULT_ERR,
NCRESULT_OK,
};
pub use plane::{
NCBLIT_1x1, NCBLIT_2x1, NCBLIT_2x2, NCBLIT_3x2, NCBLIT_4x1, NCBLIT_8x1, NcAlign, NcBlitter,

@ -1,20 +1,20 @@
use core::ptr::{null, null_mut};
use std::ffi::{CStr, CString};
use serial_test::serial; // serialize tests w/ nc::notcurses_init()
use serial_test::serial; // serialize tests w/ sys::notcurses_init()
use libnotcurses_sys as nc;
use libnotcurses_sys as sys;
#[test]
#[serial]
fn get_notcurses_version() {
let c_str = unsafe {
let s = nc::notcurses_version();
let s = sys::notcurses_version();
assert!(!s.is_null());
CStr::from_ptr(s)
};
let r_str = c_str.to_str().unwrap();
println!("rust-bound notcurses v{}", r_str);
print!("rust-bound notcurses v{} ", r_str);
}
#[test]
@ -22,7 +22,7 @@ fn get_notcurses_version() {
fn create_notcurses_context() {
unsafe {
let _ = libc::setlocale(libc::LC_ALL, CString::new("").unwrap().as_ptr());
let opts = nc::NotcursesOptions {
let opts = sys::NotcursesOptions {
loglevel: 0,
termtype: null(),
renderfp: null_mut(),
@ -30,10 +30,10 @@ fn create_notcurses_context() {
margin_r: 0,
margin_b: 0,
margin_l: 0,
flags: (nc::types::NCOPTION_NO_ALTERNATE_SCREEN | nc::types::NCOPTION_INHIBIT_SETLOCALE),
flags: (sys::types::NCOPTION_NO_ALTERNATE_SCREEN | sys::types::NCOPTION_INHIBIT_SETLOCALE | sys::types::NCOPTION_SUPPRESS_BANNERS),
};
let nc = nc::notcurses_init(&opts, null_mut());
nc::notcurses_stop(nc);
let nc = sys::notcurses_init(&opts, null_mut());
sys::notcurses_stop(nc);
}
}
@ -42,7 +42,7 @@ fn create_notcurses_context() {
fn create_direct_context() {
unsafe {
let _ = libc::setlocale(libc::LC_ALL, CString::new("").unwrap().as_ptr());
let nc = nc::ncdirect_init(null_mut(), null_mut(), 0);
nc::ncdirect_stop(nc);
let nc = sys::ncdirect_init(null_mut(), null_mut(), 0);
sys::ncdirect_stop(nc);
}
}

Loading…
Cancel
Save