/* You may distribute under the terms of either the GNU General Public License
* or the Artistic License (the same terms as Perl itself)
*
* (C) Paul Evans, 2011-2014 -- leonerd@leonerd.org.uk
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <tickit.h>
#include <tickit-termdrv.h>
#include <tickit-mockterm.h>
#include "linechars.inc"
#define streq(a,b) (strcmp(a,b)==0)
// UVs also have the IOK flag set
#define SvIsNumeric(sv) (SvFLAGS(sv) & (SVp_IOK|SVp_NOK))
static TickitEventType tickit_name2ev(const char *name)
{
switch(name[0]) {
case 'c':
return streq(name+1, "hange") ? TICKIT_EV_CHANGE
: -1;
case 'k':
return streq(name+1, "ey") ? TICKIT_EV_KEY
: -1;
case 'm':
return streq(name+1, "ouse") ? TICKIT_EV_MOUSE
: -1;
case 'r':
return streq(name+1, "esize") ? TICKIT_EV_RESIZE
: -1;
}
return -1;
}
static SV *newSVivpv(int iv, const char *pv)
{
SV *sv = newSViv(iv);
if(pv) { sv_setpv(sv, pv); SvPOK_on(sv); }
return sv;
}
static SV *tickit_ev2sv(TickitEventType ev)
{
const char *name = NULL;
switch(ev) {
case TICKIT_EV_CHANGE: name = "change"; break;
case TICKIT_EV_KEY: name = "key"; break;
case TICKIT_EV_MOUSE: name = "mouse"; break;
case TICKIT_EV_RESIZE: name = "resize"; break;
}
return newSVivpv(ev, name);
}
static SV *tickit_keyevtype2sv(int type)
{
const char *name = NULL;
switch(type) {
case TICKIT_KEYEV_KEY: name = "key"; break;
case TICKIT_KEYEV_TEXT: name = "text"; break;
}
return newSVivpv(type, name);
}
static SV *tickit_mouseevtype2sv(int type)
{
const char *name = NULL;
switch(type) {
case TICKIT_MOUSEEV_PRESS: name = "press"; break;
case TICKIT_MOUSEEV_DRAG: name = "drag"; break;
case TICKIT_MOUSEEV_RELEASE: name = "release"; break;
case TICKIT_MOUSEEV_WHEEL: name = "wheel"; break;
}
return newSVivpv(type, name);
}
static SV *tickit_mouseevbutton2sv(int type, int button)
{
const char *name = NULL;
if(type == TICKIT_MOUSEEV_WHEEL)
switch(button) {
case TICKIT_MOUSEWHEEL_UP: name = "up"; break;
case TICKIT_MOUSEWHEEL_DOWN: name = "down"; break;
}
return newSVivpv(button, name);
}
struct GenericEventData
{
SV *self;
CV *code;
SV *data;
};
/***************
* Tickit::Pen *
***************/
/* We need to keep our own pen observer list rather than use libtickit's event
* binds, because we need to be able to remove them by observer reference
*/
struct PenObserver {
struct PenObserver *next;
SV *observer;
SV *id;
};
typedef struct Tickit__Pen {
TickitPen *pen;
SV *self;
struct PenObserver *observers;
int event_id;
} *Tickit__Pen;
static SV *newSVpen(TickitPen *pen, char *package)
{
SV *sv = newSV(0);
Tickit__Pen self;
Newx(self, 1, struct Tickit__Pen);
sv_setref_pv(sv, package ? package : "Tickit::Pen::Immutable", self);
self->self = newSVsv(sv);
sv_rvweaken(self->self); // Avoid a cycle
self->pen = pen;
self->observers = NULL;
return sv;
}
static SV *pen_get_attr(TickitPen *pen, TickitPenAttr attr)
{
switch(tickit_pen_attrtype(attr)) {
case TICKIT_PENTYPE_BOOL:
return tickit_pen_get_bool_attr(pen, attr) ? &PL_sv_yes : &PL_sv_no;
case TICKIT_PENTYPE_INT:
return newSViv(tickit_pen_get_int_attr(pen, attr));
case TICKIT_PENTYPE_COLOUR:
return newSViv(tickit_pen_get_colour_attr(pen, attr));
}
}
static void pen_set_attr(TickitPen *pen, TickitPenAttr attr, SV *val)
{
switch(tickit_pen_attrtype(attr)) {
case TICKIT_PENTYPE_INT:
tickit_pen_set_int_attr(pen, attr, SvOK(val) ? SvIV(val) : -1);
break;
case TICKIT_PENTYPE_BOOL:
tickit_pen_set_bool_attr(pen, attr, SvOK(val) ? SvIV(val) : 0);
break;
case TICKIT_PENTYPE_COLOUR:
if(!SvPOK(val) && SvIsNumeric(val))
tickit_pen_set_colour_attr(pen, attr, SvIV(val));
else if(SvPOK(val))
tickit_pen_set_colour_attr_desc(pen, attr, SvPV_nolen(val));
else
tickit_pen_set_colour_attr(pen, attr, -1);
break;
}
}
static TickitPen *pen_from_args(SV **args, int argcount)
{
int i;
TickitPen *pen = tickit_pen_new();
for(i = 0; i < argcount; i += 2) {
const char *name = SvPV_nolen(args[i]);
SV *value = args[i+1];
TickitPenAttr attr = tickit_pen_lookup_attr(name);
if(attr != -1)
pen_set_attr(pen, attr, value);
}
return pen;
}
static void pen_set_attrs(TickitPen *pen, HV *attrs)
{
TickitPenAttr a;
for(a = 0; a < TICKIT_N_PEN_ATTRS; a++) {
const char *name = tickit_pen_attrname(a);
SV *val = hv_delete(attrs, name, strlen(name), 0);
if(!val)
continue;
if(!SvOK(val))
tickit_pen_clear_attr(pen, a);
else
pen_set_attr(pen, a, val);
}
}
static int pen_event_fn(TickitPen *pen, TickitEventType ev, void *_args, void *data)
{
Tickit__Pen self = data;
if(ev & TICKIT_EV_CHANGE) {
struct PenObserver *node;
for(node = self->observers; node; node = node->next) {
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 3);
mPUSHs(newSVsv(node->observer));
PUSHs(self->self); // not mortal
PUSHs(node->id);
PUTBACK;
call_method("on_pen_changed", G_VOID);
FREETMPS;
LEAVE;
}
}
return 1;
}
/****************
* Tickit::Rect *
****************/
typedef TickitRect *Tickit__Rect;
/* Really cheating and treading on Perl's namespace but hopefully it will be OK */
static SV *newSVrect(TickitRect *rect)
{
TickitRect *self;
Newx(self, 1, TickitRect);
*self = *rect;
return sv_setref_pv(newSV(0), "Tickit::Rect", self);
}
#define mPUSHrect(rect) PUSHs(sv_2mortal(newSVrect(rect)))
/*******************
* Tickit::RectSet *
*******************/
typedef TickitRectSet *Tickit__RectSet;
/************************
* Tickit::RenderBuffer *
************************/
typedef TickitRenderBuffer *Tickit__RenderBuffer;
/****************
* Tickit::Term *
****************/
typedef struct Tickit__Term {
TickitTerm *tt;
SV *input_handle;
SV *output_handle;
CV *output_func;
SV *self;
HV *event_ids;
} *Tickit__Term;
static TickitTermCtl term_name2ctl(const char *name)
{
switch(name[0]) {
case 'a':
return streq(name+1, "ltscreen") ? TICKIT_TERMCTL_ALTSCREEN
: -1;
case 'c':
return streq(name+1, "olors") ? TICKIT_TERMCTL_COLORS
: streq(name+1, "ursorblink") ? TICKIT_TERMCTL_CURSORBLINK
: streq(name+1, "ursorshape") ? TICKIT_TERMCTL_CURSORSHAPE
: streq(name+1, "ursorvis") ? TICKIT_TERMCTL_CURSORVIS
: -1;
case 'i':
return streq(name+1, "con_text") ? TICKIT_TERMCTL_ICON_TEXT
: streq(name+1, "contitle_text") ? TICKIT_TERMCTL_ICONTITLE_TEXT
: -1;
case 'k':
return streq(name+1, "eypad_app") ? TICKIT_TERMCTL_KEYPAD_APP
: -1;
case 'm':
return streq(name+1, "ouse") ? TICKIT_TERMCTL_MOUSE
: -1;
case 't':
return streq(name+1, "itle_text") ? TICKIT_TERMCTL_TITLE_TEXT
: -1;
}
return -1;
}
static int term_userevent_fn(TickitTerm *tt, TickitEventType ev, void *_info, void *user)
{
struct GenericEventData *data = user;
if(ev & ~TICKIT_EV_UNBIND) {
HV *argshash = newHV();
switch(ev) {
case TICKIT_EV_KEY: {
TickitKeyEventInfo *info = _info;
hv_store(argshash, "type", 4, tickit_keyevtype2sv(info->type), 0);
hv_store(argshash, "str", 3, newSVpvn_utf8(info->str, strlen(info->str), 1), 0);
hv_store(argshash, "mod", 3, newSViv(info->mod), 0);
break;
}
case TICKIT_EV_MOUSE: {
TickitMouseEventInfo *info = _info;
hv_store(argshash, "type", 4, tickit_mouseevtype2sv(info->type), 0);
hv_store(argshash, "button", 6, tickit_mouseevbutton2sv(info->type, info->button), 0);
hv_store(argshash, "line", 4, newSViv(info->line), 0);
hv_store(argshash, "col", 3, newSViv(info->col), 0);
hv_store(argshash, "mod", 3, newSViv(info->mod), 0);
break;
}
case TICKIT_EV_RESIZE: {
TickitResizeEventInfo *info = _info;
hv_store(argshash, "lines", 5, newSViv(info->lines), 0);
hv_store(argshash, "cols", 4, newSViv(info->cols), 0);
break;
}
// These don't happen to terminal
case TICKIT_EV_CHANGE:
SvREFCNT_dec(argshash);
return 0;
}
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 4);
PUSHs(data->self);
mPUSHs(tickit_ev2sv(ev));
mPUSHs(newRV_noinc((SV*)argshash));
mPUSHs(newSVsv(data->data));
PUTBACK;
call_sv((SV*)(data->code), G_VOID);
FREETMPS;
LEAVE;
}
if(ev & TICKIT_EV_UNBIND) {
SvREFCNT_dec(data->self);
SvREFCNT_dec(data->code);
SvREFCNT_dec(data->data);
Safefree(data);
}
return 1;
}
static void term_output_fn(TickitTerm *tt, const char *bytes, size_t len, void *user)
{
Tickit__Term self = user;
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
EXTEND(SP, 1);
mPUSHp(bytes, len);
PUTBACK;
call_sv((SV*)(self->output_func), G_VOID);
FREETMPS;
LEAVE;
}
static SV *newSVterm(TickitTerm *tt, char *package)
{
Tickit__Term self;
SV *ret;
Newx(self, 1, struct Tickit__Term);
ret = newSV(0);
sv_setref_pv(ret, package, self);
self->self = newSVsv(ret);
sv_rvweaken(self->self); // Avoid a cycle
self->tt = tt;
self->input_handle = NULL;
self->output_handle = NULL;
self->output_func = NULL;
self->event_ids = newHV();
return ret;
}
/*********************
* Tickit::StringPos *
*********************/
typedef TickitStringPos *Tickit__StringPos;
static Tickit__StringPos new_stringpos(SV **svp)
{
TickitStringPos *pos;
Newx(pos, 1, TickitStringPos);
*svp = newSV(0);
sv_setref_pv(*svp, "Tickit::StringPos", pos);
return pos;
}
static void setup_constants(void)
{
HV *stash;
AV *export;
stash = gv_stashpvn("Tickit::Term", 12, TRUE);
export = get_av("Tickit::Term::EXPORT_OK", TRUE);
#define DO_CONSTANT(c) \
newCONSTSUB(stash, #c+7, newSViv(c)); \
av_push(export, newSVpv(#c+7, 0));
DO_CONSTANT(TICKIT_TERMCTL_ALTSCREEN)
DO_CONSTANT(TICKIT_TERMCTL_CURSORVIS)
DO_CONSTANT(TICKIT_TERMCTL_CURSORBLINK)
DO_CONSTANT(TICKIT_TERMCTL_CURSORSHAPE)
DO_CONSTANT(TICKIT_TERMCTL_ICON_TEXT)
DO_CONSTANT(TICKIT_TERMCTL_ICONTITLE_TEXT)
DO_CONSTANT(TICKIT_TERMCTL_KEYPAD_APP)
DO_CONSTANT(TICKIT_TERMCTL_MOUSE)
DO_CONSTANT(TICKIT_TERMCTL_TITLE_TEXT)
DO_CONSTANT(TICKIT_TERMCTL_COLORS)
DO_CONSTANT(TICKIT_CURSORSHAPE_BLOCK)
DO_CONSTANT(TICKIT_CURSORSHAPE_UNDER)
DO_CONSTANT(TICKIT_CURSORSHAPE_LEFT_BAR)
DO_CONSTANT(TICKIT_TERM_MOUSEMODE_OFF)
DO_CONSTANT(TICKIT_TERM_MOUSEMODE_CLICK)
DO_CONSTANT(TICKIT_TERM_MOUSEMODE_DRAG)
DO_CONSTANT(TICKIT_TERM_MOUSEMODE_MOVE)
DO_CONSTANT(TICKIT_MOD_SHIFT)
DO_CONSTANT(TICKIT_MOD_ALT)
DO_CONSTANT(TICKIT_MOD_CTRL)
}
MODULE = Tickit PACKAGE = Tickit::Debug
bool
_enabled()
CODE:
RETVAL = tickit_debug_enabled;
OUTPUT:
RETVAL
void
_log(flag, message)
char *flag
char *message
CODE:
tickit_debug_logf(flag, "%s", message);
MODULE = Tickit PACKAGE = Tickit::Pen
SV *
_new(package, attrs)
char *package
HV *attrs
INIT:
Tickit__Pen self;
TickitPen *pen;
CODE:
pen = tickit_pen_new();
if(!pen)
XSRETURN_UNDEF;
pen_set_attrs(pen, attrs);
RETVAL = newSVpen(pen, package);
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::Pen self
CODE:
tickit_pen_destroy(self->pen);
SvREFCNT_dec(self->self);
while(self->observers) {
struct PenObserver *here = self->observers;
self->observers = here->next;
SvREFCNT_dec(here->observer);
SvREFCNT_dec(here->id);
Safefree(here);
}
Safefree(self);
bool
hasattr(self,attr)
Tickit::Pen self
char *attr
INIT:
TickitPenAttr a;
CODE:
if((a = tickit_pen_lookup_attr(attr)) == -1)
XSRETURN_UNDEF;
RETVAL = tickit_pen_has_attr(self->pen, a);
OUTPUT:
RETVAL
SV *
getattr(self,attr)
Tickit::Pen self
char *attr
INIT:
TickitPenAttr a;
CODE:
if((a = tickit_pen_lookup_attr(attr)) == -1)
XSRETURN_UNDEF;
if(!tickit_pen_has_attr(self->pen, a))
XSRETURN_UNDEF;
RETVAL = pen_get_attr(self->pen, a);
OUTPUT:
RETVAL
void
getattrs(self)
Tickit::Pen self
INIT:
TickitPenAttr a;
int count = 0;
PPCODE:
for(a = 0; a < TICKIT_N_PEN_ATTRS; a++) {
if(!tickit_pen_has_attr(self->pen, a))
continue;
EXTEND(SP, 2); count += 2;
/* Because mPUSHp(str,0) creates a 0-length string */
mPUSHs(newSVpv(tickit_pen_attrname(a), 0));
mPUSHs(pen_get_attr(self->pen, a));
}
XSRETURN(count);
bool
equiv_attr(self,other,attr)
Tickit::Pen self
Tickit::Pen other
char *attr
INIT:
TickitPenAttr a;
CODE:
if((a = tickit_pen_lookup_attr(attr)) == -1)
XSRETURN_UNDEF;
RETVAL = tickit_pen_equiv_attr(self->pen, other->pen, a);
OUTPUT:
RETVAL
bool
equiv(self,other)
Tickit::Pen self
Tickit::Pen other
CODE:
RETVAL = tickit_pen_equiv(self->pen, other->pen);
OUTPUT:
RETVAL
MODULE = Tickit PACKAGE = Tickit::Pen::Mutable
void
chattr(self,attr,value)
Tickit::Pen self
char *attr
SV *value
INIT:
TickitPenAttr a;
CODE:
if((a = tickit_pen_lookup_attr(attr)) == -1)
XSRETURN_UNDEF;
if(!SvOK(value)) {
tickit_pen_clear_attr(self->pen, a);
XSRETURN_UNDEF;
}
pen_set_attr(self->pen, a, value);
void
chattrs(self,attrs)
Tickit::Pen self
HV *attrs
CODE:
pen_set_attrs(self->pen, attrs);
void
delattr(self,attr)
Tickit::Pen self
char *attr
INIT:
TickitPenAttr a;
CODE:
if((a = tickit_pen_lookup_attr(attr)) == -1)
XSRETURN_UNDEF;
tickit_pen_clear_attr(self->pen, a);
void
copy(self,other,overwrite)
Tickit::Pen self
Tickit::Pen other
int overwrite
CODE:
tickit_pen_copy(self->pen, other->pen, overwrite);
void
add_on_changed(self,observer,id=&PL_sv_undef)
Tickit::Pen self
SV *observer
SV *id
INIT:
struct PenObserver *node;
CODE:
if(!SvROK(observer))
croak("Expected observer to be a reference");
if(ckWARN(WARN_DEPRECATED))
warn("Use of pen on_changed observers is now deprecated");
Newx(node, 1, struct PenObserver);
node->observer = sv_rvweaken(newSVsv(observer));
node->id = newSVsv(id);
node->next = NULL;
if(self->observers) {
struct PenObserver *link = self->observers;
while(link->next)
link = link->next;
link->next = node;
}
else {
self->event_id = tickit_pen_bind_event(self->pen, TICKIT_EV_CHANGE, pen_event_fn, self);
self->observers = node;
}
void
remove_on_changed(self,observer)
Tickit::Pen self
SV *observer
INIT:
struct PenObserver **herep;
CODE:
herep = &self->observers;
while(*herep) {
struct PenObserver *here = (*herep);
if(SvRV(observer) != SvRV(here->observer)) {
herep = &here->next;
continue;
}
*herep = here->next;
SvREFCNT_dec(here->observer);
SvREFCNT_dec(here->id);
Safefree(here);
}
if(self->event_id && !self->observers) {
tickit_pen_unbind_event_id(self->pen, self->event_id);
self->event_id = 0;
}
MODULE = Tickit PACKAGE = Tickit::Rect
Tickit::Rect
_new(package,top,left,lines,cols)
char *package
int top
int left
int lines
int cols
CODE:
Newx(RETVAL, 1, TickitRect);
tickit_rect_init_sized(RETVAL, top, left, lines, cols);
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::Rect self
CODE:
Safefree(self);
Tickit::Rect
intersect(self,other)
Tickit::Rect self
Tickit::Rect other
INIT:
TickitRect ret;
CODE:
if(!tickit_rect_intersect(&ret, self, other))
XSRETURN_UNDEF;
Newx(RETVAL, 1, TickitRect);
*RETVAL = ret;
OUTPUT:
RETVAL
Tickit::Rect
translate(self,downward,rightward)
Tickit::Rect self
int downward
int rightward
CODE:
Newx(RETVAL, 1, TickitRect);
tickit_rect_init_sized(RETVAL, self->top + downward, self->left + rightward,
self->lines, self->cols);
OUTPUT:
RETVAL
int
top(self)
Tickit::Rect self
CODE:
RETVAL = self->top;
OUTPUT:
RETVAL
int
left(self)
Tickit::Rect self
CODE:
RETVAL = self->left;
OUTPUT:
RETVAL
int
lines(self)
Tickit::Rect self
CODE:
RETVAL = self->lines;
OUTPUT:
RETVAL
int
cols(self)
Tickit::Rect self
CODE:
RETVAL = self->cols;
OUTPUT:
RETVAL
int
bottom(self)
Tickit::Rect self
CODE:
RETVAL = tickit_rect_bottom(self);
OUTPUT:
RETVAL
int
right(self)
Tickit::Rect self
CODE:
RETVAL = tickit_rect_right(self);
OUTPUT:
RETVAL
bool
equals(self,other,swap=0)
Tickit::Rect self
Tickit::Rect other
int swap
CODE:
RETVAL = (self->top == other->top) &&
(self->lines == other->lines) &&
(self->left == other->left) &&
(self->cols == other->cols);
OUTPUT:
RETVAL
bool
intersects(self,other)
Tickit::Rect self
Tickit::Rect other
CODE:
RETVAL = tickit_rect_intersects(self, other);
OUTPUT:
RETVAL
bool
contains(large,small)
Tickit::Rect large
Tickit::Rect small
CODE:
RETVAL = tickit_rect_contains(large, small);
OUTPUT:
RETVAL
void
add(x,y)
Tickit::Rect x
Tickit::Rect y
INIT:
int n_rects, i;
TickitRect rects[3];
PPCODE:
n_rects = tickit_rect_add(rects, x, y);
for(i = 0; i < n_rects; i++)
mPUSHrect(rects + i);
XSRETURN(n_rects);
void
subtract(self,hole)
Tickit::Rect self
Tickit::Rect hole
INIT:
int n_rects, i;
TickitRect rects[4];
PPCODE:
n_rects = tickit_rect_subtract(rects, self, hole);
for(i = 0; i < n_rects; i++)
mPUSHrect(rects + i);
XSRETURN(n_rects);
MODULE = Tickit PACKAGE = Tickit::RectSet
Tickit::RectSet
new(package)
char *package
CODE:
RETVAL = tickit_rectset_new();
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::RectSet self
CODE:
tickit_rectset_destroy(self);
void
clear(self)
Tickit::RectSet self
CODE:
tickit_rectset_clear(self);
void
rects(self)
Tickit::RectSet self
INIT:
int n;
TickitRect *rects;
int i;
PPCODE:
n = tickit_rectset_rects(self);
if(GIMME_V != G_ARRAY) {
mPUSHi(n);
XSRETURN(1);
}
Newx(rects, n, TickitRect);
tickit_rectset_get_rects(self, rects, n);
EXTEND(SP, n);
for(i = 0; i < n; i++) {
mPUSHrect(rects + i);
}
Safefree(rects);
XSRETURN(n);
void
add(self,rect)
Tickit::RectSet self
Tickit::Rect rect
CODE:
tickit_rectset_add(self, rect);
void
subtract(self,rect)
Tickit::RectSet self
Tickit::Rect rect
CODE:
tickit_rectset_subtract(self, rect);
bool
intersects(self,r)
Tickit::RectSet self
Tickit::Rect r
INIT:
int i;
CODE:
RETVAL = tickit_rectset_intersects(self, r);
OUTPUT:
RETVAL
bool
contains(self,r)
Tickit::RectSet self
Tickit::Rect r
INIT:
int i;
CODE:
RETVAL = tickit_rectset_contains(self, r);
OUTPUT:
RETVAL
MODULE = Tickit PACKAGE = Tickit::RenderBuffer
Tickit::RenderBuffer
_xs_new(class,lines,cols)
char *class
int lines
int cols
CODE:
RETVAL = tickit_renderbuffer_new(lines, cols);
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_destroy(self);
int
lines(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_get_size(self, &RETVAL, NULL);
OUTPUT:
RETVAL
int
cols(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_get_size(self, NULL, &RETVAL);
OUTPUT:
RETVAL
SV *
line(self)
Tickit::RenderBuffer self
INIT:
TickitRenderBuffer *rb;
CODE:
rb = self;
if(tickit_renderbuffer_has_cursorpos(rb)) {
int line;
tickit_renderbuffer_get_cursorpos(rb, &line, NULL);
RETVAL = newSViv(line);
}
else
RETVAL = &PL_sv_undef;
OUTPUT:
RETVAL
SV *
col(self)
Tickit::RenderBuffer self
INIT:
TickitRenderBuffer *rb;
CODE:
rb = self;
if(tickit_renderbuffer_has_cursorpos(rb)) {
int col;
tickit_renderbuffer_get_cursorpos(rb, NULL, &col);
RETVAL = newSViv(col);
}
else
RETVAL = &PL_sv_undef;
OUTPUT:
RETVAL
void
translate(self,downward,rightward)
Tickit::RenderBuffer self
int downward
int rightward
PPCODE:
tickit_renderbuffer_translate(self, downward, rightward);
void
clip(self,rect)
Tickit::RenderBuffer self
Tickit::Rect rect
CODE:
tickit_renderbuffer_clip(self, rect);
void
mask(self,rect)
Tickit::RenderBuffer self
Tickit::Rect rect
CODE:
tickit_renderbuffer_mask(self, rect);
void
goto(self,line,col)
Tickit::RenderBuffer self
SV *line
SV *col
CODE:
if(SvIsNumeric(line) && SvIsNumeric(col))
tickit_renderbuffer_goto(self, SvIV(line), SvIV(col));
else
tickit_renderbuffer_ungoto(self);
void
setpen(self,pen)
Tickit::RenderBuffer self
Tickit::Pen pen
CODE:
tickit_renderbuffer_setpen(self, pen ? pen->pen : NULL);
void
reset(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_reset(self);
void
clear(self,pen=NULL)
Tickit::RenderBuffer self
Tickit::Pen pen
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_clear(self);
if(pen)
tickit_renderbuffer_restore(self);
void
save(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_save(self);
void
savepen(self)
Tickit::RenderBuffer self
CODE:
tickit_renderbuffer_savepen(self);
void
restore(self)
Tickit::RenderBuffer self
INIT:
TickitRenderBuffer *rb;
CODE:
tickit_renderbuffer_restore(self);
void
_xs_get_cell(self,line,col)
Tickit::RenderBuffer self
int line
int col
INIT:
TickitRenderBuffer *rb;
STRLEN len;
SV *text;
TickitRenderBufferLineMask mask;
PPCODE:
rb = self;
if(tickit_renderbuffer_get_cell_active(rb, line, col) != 1) {
XPUSHs(&PL_sv_undef);
XPUSHs(&PL_sv_undef);
XSRETURN(2);
}
len = tickit_renderbuffer_get_cell_text(rb, line, col, NULL, 0);
text = newSV(len + 1);
tickit_renderbuffer_get_cell_text(rb, line, col, SvPVX(text), len + 1);
SvPOK_on(text); SvUTF8_on(text); SvCUR_set(text, len);
XPUSHs(sv_2mortal(text));
mPUSHs(newSVpen(tickit_pen_clone(tickit_renderbuffer_get_cell_pen(rb, line, col)), NULL));
mask = tickit_renderbuffer_get_cell_linemask(rb, line, col);
if(!mask.north && !mask.south && !mask.east && !mask.west)
XSRETURN(2);
mPUSHi(mask.north);
mPUSHi(mask.south);
mPUSHi(mask.east);
mPUSHi(mask.west);
XSRETURN(6);
void
skip_at(self,line,col,len)
Tickit::RenderBuffer self
int line
int col
int len
CODE:
tickit_renderbuffer_skip_at(self, line, col, len);
void
skip(self,len)
Tickit::RenderBuffer self
int len
CODE:
if(!tickit_renderbuffer_has_cursorpos(self))
croak("Cannot ->skip without a virtual cursor position");
tickit_renderbuffer_skip(self, len);
void
skip_to(self,col)
Tickit::RenderBuffer self
int col
CODE:
if(!tickit_renderbuffer_has_cursorpos(self))
croak("Cannot ->skip_to without a virtual cursor position");
tickit_renderbuffer_skip_to(self, col);
int
text_at(self,line,col,text,pen=NULL)
Tickit::RenderBuffer self
int line
int col
SV *text
Tickit::Pen pen
INIT:
STRLEN len;
CODE:
SvGETMAGIC(text);
len = SvCUR(text);
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
RETVAL = tickit_renderbuffer_textn_at(self, line, col, SvPVutf8_nolen(text), len);
if(pen)
tickit_renderbuffer_restore(self);
OUTPUT:
RETVAL
int
text(self,text,pen=NULL)
Tickit::RenderBuffer self
SV *text
Tickit::Pen pen
INIT:
STRLEN len;
CODE:
if(!tickit_renderbuffer_has_cursorpos(self))
croak("Cannot ->text without a virtual cursor position");
SvGETMAGIC(text);
len = SvCUR(text);
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
RETVAL = tickit_renderbuffer_textn(self, SvPVutf8_nolen(text), len);
if(pen)
tickit_renderbuffer_restore(self);
OUTPUT:
RETVAL
void
erase_at(self,line,col,len,pen=NULL)
Tickit::RenderBuffer self
int line
int col
int len
Tickit::Pen pen
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_erase_at(self, line, col, len);
if(pen)
tickit_renderbuffer_restore(self);
void
erase(self,len,pen=NULL)
Tickit::RenderBuffer self
int len
Tickit::Pen pen
CODE:
if(!tickit_renderbuffer_has_cursorpos(self))
croak("Cannot ->erase without a virtual cursor position");
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_erase(self, len);
if(pen)
tickit_renderbuffer_restore(self);
void
erase_to(self,col,pen=NULL)
Tickit::RenderBuffer self
int col
Tickit::Pen pen
CODE:
if(!tickit_renderbuffer_has_cursorpos(self))
croak("Cannot ->erase_to without a virtual cursor position");
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_erase_to(self, col);
if(pen)
tickit_renderbuffer_restore(self);
void
eraserect(self,rect,pen=NULL)
Tickit::RenderBuffer self
Tickit::Rect rect
Tickit::Pen pen
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_eraserect(self, rect);
if(pen)
tickit_renderbuffer_restore(self);
void
char_at(self,line,col,codepoint,pen=NULL)
Tickit::RenderBuffer self
int line
int col
int codepoint
Tickit::Pen pen
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_char_at(self, line, col, codepoint);
if(pen)
tickit_renderbuffer_restore(self);
void
char(self,codepoint,pen=NULL)
Tickit::RenderBuffer self
int codepoint
Tickit::Pen pen
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_char(self, codepoint);
if(pen)
tickit_renderbuffer_restore(self);
void
hline_at(self,line,startcol,endcol,style,pen=NULL,caps=0)
Tickit::RenderBuffer self
int line
int startcol
int endcol
int style
Tickit::Pen pen
int caps
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_hline_at(self, line, startcol, endcol, style, caps);
if(pen)
tickit_renderbuffer_restore(self);
void
vline_at(self,startline,endline,col,style,pen=NULL,caps=0)
Tickit::RenderBuffer self
int startline
int endline
int col
int style
Tickit::Pen pen
int caps
CODE:
if(pen) {
tickit_renderbuffer_savepen(self);
tickit_renderbuffer_setpen(self, pen->pen);
}
tickit_renderbuffer_vline_at(self, startline, endline, col, style, caps);
if(pen)
tickit_renderbuffer_restore(self);
void
flush_to_term(self,term)
Tickit::RenderBuffer self
Tickit::Term term
CODE:
tickit_renderbuffer_flush_to_term(self, term->tt);
MODULE = Tickit PACKAGE = Tickit::StringPos
SV *
zero(package)
char *package;
INIT:
TickitStringPos *pos;
CODE:
pos = new_stringpos(&RETVAL);
tickit_stringpos_zero(pos);
OUTPUT:
RETVAL
SV *
limit_bytes(package,bytes)
char *package;
size_t bytes;
INIT:
TickitStringPos *pos;
CODE:
pos = new_stringpos(&RETVAL);
tickit_stringpos_limit_bytes(pos, bytes);
OUTPUT:
RETVAL
SV *
limit_codepoints(package,codepoints)
char *package;
int codepoints;
INIT:
TickitStringPos *pos;
CODE:
pos = new_stringpos(&RETVAL);
tickit_stringpos_limit_codepoints(pos, codepoints);
OUTPUT:
RETVAL
SV *
limit_graphemes(package,graphemes)
char *package;
int graphemes;
INIT:
TickitStringPos *pos;
CODE:
pos = new_stringpos(&RETVAL);
tickit_stringpos_limit_graphemes(pos, graphemes);
OUTPUT:
RETVAL
SV *
limit_columns(package,columns)
char *package;
int columns;
INIT:
TickitStringPos *pos;
CODE:
pos = new_stringpos(&RETVAL);
tickit_stringpos_limit_columns(pos, columns);
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::StringPos self
CODE:
Safefree(self);
size_t
bytes(self)
Tickit::StringPos self;
CODE:
RETVAL = self->bytes;
OUTPUT:
RETVAL
int
codepoints(self)
Tickit::StringPos self;
CODE:
RETVAL = self->codepoints;
OUTPUT:
RETVAL
int
graphemes(self)
Tickit::StringPos self;
CODE:
RETVAL = self->graphemes;
OUTPUT:
RETVAL
int
columns(self)
Tickit::StringPos self;
CODE:
RETVAL = self->columns;
OUTPUT:
RETVAL
MODULE = Tickit PACKAGE = Tickit::Term
SV *
_new(package,termtype)
char *package;
char *termtype;
INIT:
Tickit__Term self;
TickitTerm *tt;
CODE:
tt = tickit_term_new_for_termtype(termtype);
if(!tt)
XSRETURN_UNDEF;
RETVAL = newSVterm(tt, package);
OUTPUT:
RETVAL
void
DESTROY(self)
Tickit::Term self
CODE:
/*
* destroy TickitTerm first in case it's still using output_handle/func
*/
tickit_term_destroy(self->tt);
if(self->input_handle)
SvREFCNT_dec(self->input_handle);
if(self->output_handle)
SvREFCNT_dec(self->output_handle);
if(self->output_func)
SvREFCNT_dec(self->output_func);
if(self->event_ids)
SvREFCNT_dec(self->event_ids);
SvREFCNT_dec(self->self);
Safefree(self);
SV *
get_input_handle(self)
Tickit::Term self
CODE:
if(self->input_handle)
RETVAL = newRV_inc(self->input_handle);
else
XSRETURN_UNDEF;
OUTPUT:
RETVAL
void
set_input_handle(self,handle)
Tickit::Term self
SV *handle
CODE:
if(self->input_handle)
SvREFCNT_dec(self->input_handle);
self->input_handle = SvREFCNT_inc(SvRV(handle));
tickit_term_set_input_fd(self->tt, PerlIO_fileno(IoIFP(sv_2io(handle))));
SV *
get_output_handle(self)
Tickit::Term self
CODE:
if(self->output_handle)
RETVAL = newRV_inc(self->output_handle);
else
XSRETURN_UNDEF;
OUTPUT:
RETVAL
void
set_output_handle(self,handle)
Tickit::Term self
SV *handle
CODE:
if(self->output_handle)
SvREFCNT_dec(self->output_handle);
self->output_handle = SvREFCNT_inc(SvRV(handle));
tickit_term_set_output_fd(self->tt, PerlIO_fileno(IoIFP(sv_2io(handle))));
void
set_output_func(self,func)
Tickit::Term self
CV *func
CODE:
if(self->output_func)
SvREFCNT_dec(self->output_func);
self->output_func = (CV*)SvREFCNT_inc(func);
tickit_term_set_output_func(self->tt, term_output_fn, self);
void
await_started(self,timeout)
Tickit::Term self
double timeout
CODE:
tickit_term_await_started_msec(self->tt, timeout * 1000);
void
flush(self)
Tickit::Term self
CODE:
tickit_term_flush(self->tt);
void
set_output_buffer(self,len)
Tickit::Term self
size_t len
CODE:
tickit_term_set_output_buffer(self->tt, len);
void
set_utf8(self,utf8)
Tickit::Term self
int utf8;
CODE:
tickit_term_set_utf8(self->tt, utf8);
void
get_size(self)
Tickit::Term self
INIT:
int lines, cols;
PPCODE:
tickit_term_get_size(self->tt, &lines, &cols);
EXTEND(SP, 2);
mPUSHi(lines);
mPUSHi(cols);
XSRETURN(2);
void
set_size(self,lines,cols)
Tickit::Term self
int lines
int cols
CODE:
tickit_term_set_size(self->tt, lines, cols);
void
refresh_size(self)
Tickit::Term self
CODE:
tickit_term_refresh_size(self->tt);
int
bind_event(self,ev,code,data = &PL_sv_undef)
Tickit::Term self
char *ev
CV *code
SV *data
INIT:
TickitEventType ev_e;
struct GenericEventData *user;
CODE:
ev_e = tickit_name2ev(ev);
if(ev_e == -1)
croak("Unrecognised event name '%s'", ev);
Newx(user, 1, struct GenericEventData);
user->self = SvREFCNT_inc(self->self);
user->code = (CV*)SvREFCNT_inc(code);
user->data = newSVsv(data);
RETVAL = tickit_term_bind_event(self->tt, ev_e|TICKIT_EV_UNBIND, term_userevent_fn, user);
OUTPUT:
RETVAL
void
unbind_event_id(self,id)
Tickit::Term self
int id
CODE:
tickit_term_unbind_event_id(self->tt, id);
SV *
_event_ids(self)
Tickit::Term self
CODE:
RETVAL = newRV_inc((SV*)self->event_ids);
OUTPUT:
RETVAL
void
input_push_bytes(self,bytes)
Tickit::Term self
SV *bytes
INIT:
char *str;
STRLEN len;
CODE:
str = SvPV(bytes, len);
tickit_term_input_push_bytes(self->tt, str, len);
void
input_readable(self)
Tickit::Term self
CODE:
tickit_term_input_readable(self->tt);
void
input_wait(self,timeout=&PL_sv_undef)
Tickit::Term self
SV *timeout
CODE:
if(SvIsNumeric(timeout))
tickit_term_input_wait_msec(self->tt, SvNV(timeout) * 1000);
else
tickit_term_input_wait_msec(self->tt, -1);
SV *
check_timeout(self)
Tickit::Term self
INIT:
int msec;
CODE:
msec = tickit_term_input_check_timeout_msec(self->tt);
RETVAL = newSV(0);
if(msec >= 0)
sv_setnv(RETVAL, msec / 1000.0);
OUTPUT:
RETVAL
bool
goto(self,line,col)
Tickit::Term self
SV *line
SV *col
CODE:
RETVAL = tickit_term_goto(self->tt, SvOK(line) ? SvIV(line) : -1, SvOK(col) ? SvIV(col) : -1);
OUTPUT:
RETVAL
void
move(self,downward,rightward)
Tickit::Term self
SV *downward
SV *rightward
CODE:
tickit_term_move(self->tt, SvOK(downward) ? SvIV(downward) : 0, SvOK(rightward) ? SvIV(rightward) : 0);
int
scrollrect(self,top,left,lines,cols,downward,rightward)
Tickit::Term self
int top
int left
int lines
int cols
int downward
int rightward
INIT:
TickitRect rect;
CODE:
rect.top = top;
rect.left = left;
rect.lines = lines;
rect.cols = cols;
RETVAL = tickit_term_scrollrect(self->tt, rect, downward, rightward);
OUTPUT:
RETVAL
void
chpen(self,...)
Tickit::Term self
INIT:
TickitPen *pen;
int pen_temp = 0;
CODE:
if(items == 2 && SvROK(ST(1)) && sv_derived_from(ST(1), "Tickit::Pen")) {
IV tmp = SvIV((SV*)SvRV(ST(1)));
Tickit__Pen self = INT2PTR(Tickit__Pen, tmp);
pen = self->pen;
}
else {
pen = pen_from_args(SP-items+2, items-1);
pen_temp = 1;
}
tickit_term_chpen(self->tt, pen);
if(pen_temp)
tickit_pen_destroy(pen);
void
setpen(self,...)
Tickit::Term self
INIT:
TickitPen *pen;
int pen_temp = 0;
CODE:
if(items == 2 && SvROK(ST(1)) && sv_derived_from(ST(1), "Tickit::Pen")) {
IV tmp = SvIV((SV*)SvRV(ST(1)));
Tickit__Pen self = INT2PTR(Tickit__Pen, tmp);
pen = self->pen;
}
else {
pen = pen_from_args(SP-items+2, items-1);
pen_temp = 1;
}
tickit_term_setpen(self->tt, pen);
if(pen_temp)
tickit_pen_destroy(pen);
void
print(self,text,pen=NULL)
Tickit::Term self
SV *text
Tickit::Pen pen
INIT:
char *utf8;
STRLEN len;
CODE:
if(pen)
tickit_term_setpen(self->tt, pen->pen);
utf8 = SvPVutf8(text, len);
tickit_term_printn(self->tt, utf8, len);
void
clear(self,pen=NULL)
Tickit::Term self
Tickit::Pen pen
CODE:
if(pen)
tickit_term_setpen(self->tt, pen->pen);
tickit_term_clear(self->tt);
void
erasech(self,count,moveend,pen=NULL)
Tickit::Term self
int count
SV *moveend
Tickit::Pen pen
CODE:
if(pen)
tickit_term_setpen(self->tt, pen->pen);
tickit_term_erasech(self->tt, count, SvOK(moveend) ? SvIV(moveend) : -1);
int
getctl_int(self,ctl)
Tickit::Term self
SV *ctl
INIT:
TickitTermCtl ctl_e;
CODE:
if(SvPOK(ctl)) {
ctl_e = term_name2ctl(SvPV_nolen(ctl));
if(ctl_e == -1)
croak("Unrecognised 'ctl' name '%s'", SvPV_nolen(ctl));
}
else if(SvIOK(ctl))
ctl_e = SvIV(ctl);
else
croak("Expected 'ctl' to be an integer or string");
if(!tickit_term_getctl_int(self->tt, ctl_e, &RETVAL))
XSRETURN_UNDEF;
OUTPUT:
RETVAL
void
setctl_int(self,ctl,value)
Tickit::Term self
SV *ctl
int value
INIT:
TickitTermCtl ctl_e;
PPCODE:
if(SvPOK(ctl)) {
ctl_e = term_name2ctl(SvPV_nolen(ctl));
if(ctl_e == -1)
croak("Unrecognised 'ctl' name '%s'", SvPV_nolen(ctl));
}
else if(SvIOK(ctl))
ctl_e = SvIV(ctl);
else
croak("Expected 'ctl' to be an integer or string");
if(tickit_term_setctl_int(self->tt, ctl_e, value))
XSRETURN_YES;
else
XSRETURN_NO;
int
setctl_str(self,ctl,value)
Tickit::Term self
SV *ctl
char *value
INIT:
TickitTermCtl ctl_e;
CODE:
if(SvPOK(ctl)) {
ctl_e = term_name2ctl(SvPV_nolen(ctl));
if(ctl_e == -1)
croak("Unrecognised 'ctl' name '%s'", SvPV_nolen(ctl));
}
else if(SvIOK(ctl))
ctl_e = SvIV(ctl);
else
croak("Expected 'ctl' to be an integer or string");
RETVAL = tickit_term_setctl_str(self->tt, ctl_e, value);
OUTPUT:
RETVAL
MODULE = Tickit::Test::MockTerm PACKAGE = Tickit::Test::MockTerm
SV *
_new_mocking(package,lines,cols)
char *package
int lines
int cols
INIT:
TickitMockTerm *mt;
CODE:
mt = tickit_mockterm_new(lines, cols);
if(!mt)
XSRETURN_UNDEF;
RETVAL = newSVterm((TickitTerm *)mt, "Tickit::Test::MockTerm");
OUTPUT:
RETVAL
void
get_methodlog(self)
Tickit::Term self
INIT:
TickitMockTerm *mt;
int loglen;
int i;
PPCODE:
mt = (TickitMockTerm *)self->tt;
EXTEND(SP, (loglen = tickit_mockterm_loglen(mt)));
for(i = 0; i < loglen; i++) {
TickitMockTermLogEntry *entry = tickit_mockterm_peeklog(mt, i);
AV *ret = newAV();
switch(entry->type) {
case LOG_GOTO:
av_push(ret, newSVpv("goto", 0));
av_push(ret, newSViv(entry->val1)); // line
av_push(ret, newSViv(entry->val2)); // col
break;
case LOG_PRINT:
av_push(ret, newSVpv("print", 0));
av_push(ret, newSVpvn_utf8(entry->str, entry->val1, 1));
break;
case LOG_ERASECH:
av_push(ret, newSVpv("erasech", 0));
av_push(ret, newSViv(entry->val1)); // count
av_push(ret, newSViv(entry->val2 == 1 ? 1 : 0)); // moveend
break;
case LOG_CLEAR:
av_push(ret, newSVpv("clear", 0));
break;
case LOG_SCROLLRECT:
av_push(ret, newSVpv("scrollrect", 0));
av_push(ret, newSViv(entry->rect.top));
av_push(ret, newSViv(entry->rect.left));
av_push(ret, newSViv(entry->rect.lines));
av_push(ret, newSViv(entry->rect.cols));
av_push(ret, newSViv(entry->val1)); // downward
av_push(ret, newSViv(entry->val2)); // rightward
break;
case LOG_SETPEN:
{
HV *penattrs = newHV();
TickitPenAttr attr;
for(attr = 0; attr < TICKIT_N_PEN_ATTRS; attr++) {
const char *attrname = tickit_pen_attrname(attr);
int value;
if(!tickit_pen_nondefault_attr(entry->pen, attr))
continue;
switch(tickit_pen_attrtype(attr)) {
case TICKIT_PENTYPE_BOOL:
value = tickit_pen_get_bool_attr(entry->pen, attr); break;
case TICKIT_PENTYPE_INT:
value = tickit_pen_get_int_attr(entry->pen, attr); break;
case TICKIT_PENTYPE_COLOUR:
value = tickit_pen_get_colour_attr(entry->pen, attr); break;
}
sv_setiv(*hv_fetch(penattrs, attrname, strlen(attrname), 1), value);
}
av_push(ret, newSVpv("setpen", 0));
av_push(ret, newRV_noinc((SV *)penattrs));
}
break;
}
mPUSHs(newRV_noinc((SV *)ret));
}
tickit_mockterm_clearlog(mt);
XSRETURN(i);
SV *
get_display_text(self,line,col,width)
Tickit::Term self
int line
int col
int width
INIT:
STRLEN len;
CODE:
len = tickit_mockterm_get_display_text((TickitMockTerm *)self->tt, NULL, 0, line, col, width);
RETVAL = newSV(len+1);
tickit_mockterm_get_display_text((TickitMockTerm *)self->tt, SvPVX(RETVAL), len, line, col, width);
SvPOK_on(RETVAL);
SvUTF8_on(RETVAL);
SvCUR_set(RETVAL, len);
OUTPUT:
RETVAL
SV *
get_display_pen(self,line,col)
Tickit::Term self
int line
int col
INIT:
TickitPen *pen;
HV *penattrs;
TickitPenAttr attr;
CODE:
pen = tickit_mockterm_get_display_pen((TickitMockTerm *)self->tt, line, col);
penattrs = newHV();
for(attr = 0; attr < TICKIT_N_PEN_ATTRS; attr++) {
const char *attrname;
if(!tickit_pen_nondefault_attr(pen, attr))
continue;
attrname = tickit_pen_attrname(attr);
hv_store(penattrs, attrname, strlen(attrname), pen_get_attr(pen, attr), 0);
}
RETVAL = newRV_noinc((SV *)penattrs);
OUTPUT:
RETVAL
void
resize(self,newlines,newcols)
Tickit::Term self
int newlines
int newcols
CODE:
tickit_mockterm_resize((TickitMockTerm *)self->tt, newlines, newcols);
int
line(self)
Tickit::Term self
ALIAS:
line = 0
col = 1
cursorvis = 2
cursorshape = 3
INIT:
TickitMockTerm *mt;
CODE:
mt = (TickitMockTerm *)self->tt;
switch(ix) {
case 0: tickit_mockterm_get_position(mt, &RETVAL, NULL); break;
case 1: tickit_mockterm_get_position(mt, NULL, &RETVAL); break;
case 2: tickit_term_getctl_int(self->tt, TICKIT_TERMCTL_CURSORVIS, &RETVAL); break;
case 3: tickit_term_getctl_int(self->tt, TICKIT_TERMCTL_CURSORSHAPE, &RETVAL); break;
}
OUTPUT:
RETVAL
MODULE = Tickit PACKAGE = Tickit::Utils
size_t
string_count(str,pos,limit=NULL)
SV *str
Tickit::StringPos pos
Tickit::StringPos limit
INIT:
char *s;
STRLEN len;
CODE:
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPVutf8(str, len);
RETVAL = tickit_string_ncount(s, len, pos, limit);
if(RETVAL == -1)
XSRETURN_UNDEF;
OUTPUT:
RETVAL
size_t
string_countmore(str,pos,limit=NULL)
SV *str
Tickit::StringPos pos
Tickit::StringPos limit
INIT:
char *s;
STRLEN len;
CODE:
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPVutf8(str, len);
RETVAL = tickit_string_ncountmore(s, len, pos, limit);
if(RETVAL == -1)
XSRETURN_UNDEF;
OUTPUT:
RETVAL
int textwidth(str)
SV *str
INIT:
STRLEN len;
const char *s;
TickitStringPos pos, limit = INIT_TICKIT_STRINGPOS_LIMIT_NONE;
CODE:
RETVAL = 0;
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPVutf8(str, len);
if(tickit_string_ncount(s, len, &pos, &limit) == -1)
XSRETURN_UNDEF;
RETVAL = pos.columns;
OUTPUT:
RETVAL
void chars2cols(str,...)
SV *str;
INIT:
STRLEN len;
const char *s;
int i;
TickitStringPos pos, limit;
size_t bytes;
PPCODE:
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPVutf8(str, len);
EXTEND(SP, items - 1);
tickit_stringpos_zero(&pos);
tickit_stringpos_limit_bytes(&limit, len);
for(i = 1; i < items; i++ ) {
limit.codepoints = SvUV(ST(i));
if(limit.codepoints < pos.codepoints)
croak("chars2cols requires a monotonically-increasing list of character numbers; %d is not greater than %d\n",
limit.codepoints, pos.codepoints);
bytes = tickit_string_ncountmore(s, len, &pos, &limit);
if(bytes == -1)
XSRETURN_UNDEF;
mPUSHu(pos.columns);
if(GIMME_V != G_ARRAY)
XSRETURN(1);
}
XSRETURN(items - 1);
void cols2chars(str,...)
SV *str;
INIT:
STRLEN len;
const char *s;
int i;
TickitStringPos pos, limit;
size_t bytes;
PPCODE:
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPVutf8(str, len);
EXTEND(SP, items - 1);
tickit_stringpos_zero(&pos);
tickit_stringpos_limit_bytes(&limit, len);
for(i = 1; i < items; i++ ) {
limit.columns = SvUV(ST(i));
if(limit.columns < pos.columns)
croak("cols2chars requires a monotonically-increasing list of column numbers; %d is not greater than %d\n",
limit.columns, pos.columns);
bytes = tickit_string_ncountmore(s, len, &pos, &limit);
if(bytes == -1)
XSRETURN_UNDEF;
mPUSHu(pos.codepoints);
if(GIMME_V != G_ARRAY)
XSRETURN(1);
}
XSRETURN(items - 1);
MODULE = Tickit PACKAGE = Tickit
BOOT:
setup_constants();