notcurses 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +9 -1
  5. data/Rakefile +11 -0
  6. data/Rakefile.new +28 -0
  7. data/TODO +19 -0
  8. data/checksums/notcurses-0.0.1.gem.sha512 +1 -0
  9. data/data/PurpleDrank.jpg +0 -0
  10. data/data/Windows10Logo.png +0 -0
  11. data/data/aidsrobots.jpeg +0 -0
  12. data/data/atma.png +0 -0
  13. data/data/changes.jpg +0 -0
  14. data/data/changes.xcf +0 -0
  15. data/data/chunli01.png +0 -0
  16. data/data/chunli02.png +0 -0
  17. data/data/chunli03.png +0 -0
  18. data/data/chunli04.png +0 -0
  19. data/data/chunli05.png +0 -0
  20. data/data/chunli06.png +0 -0
  21. data/data/chunli07.png +0 -0
  22. data/data/chunli08.png +0 -0
  23. data/data/chunli09.png +0 -0
  24. data/data/chunli1.bmp +0 -0
  25. data/data/chunli10.png +0 -0
  26. data/data/chunli11.png +0 -0
  27. data/data/chunli12.png +0 -0
  28. data/data/chunli13.png +0 -0
  29. data/data/chunli14.png +0 -0
  30. data/data/chunli15.png +0 -0
  31. data/data/chunli16.png +0 -0
  32. data/data/chunli17.png +0 -0
  33. data/data/chunli18.png +0 -0
  34. data/data/chunli19.png +0 -0
  35. data/data/chunli2.bmp +0 -0
  36. data/data/chunli20.png +0 -0
  37. data/data/chunli21.png +0 -0
  38. data/data/chunli22.png +0 -0
  39. data/data/chunli23.png +0 -0
  40. data/data/chunli24.png +0 -0
  41. data/data/chunli25.png +0 -0
  42. data/data/chunli26.png +0 -0
  43. data/data/chunli27.png +0 -0
  44. data/data/chunli28.png +0 -0
  45. data/data/chunli29.png +0 -0
  46. data/data/chunli3.bmp +0 -0
  47. data/data/chunli30.png +0 -0
  48. data/data/chunli31.png +0 -0
  49. data/data/chunli32.png +1 -0
  50. data/data/chunli33.png +1 -0
  51. data/data/chunli34.png +1 -0
  52. data/data/chunli35.png +1 -0
  53. data/data/chunli36.png +1 -0
  54. data/data/chunli37.png +1 -0
  55. data/data/chunli38.png +0 -0
  56. data/data/chunli39.png +1 -0
  57. data/data/chunli4.bmp +0 -0
  58. data/data/chunli40.png +0 -0
  59. data/data/chunli41.png +1 -0
  60. data/data/chunli42.png +1 -0
  61. data/data/chunli43.png +1 -0
  62. data/data/chunli44.png +1 -0
  63. data/data/chunli45.png +0 -0
  64. data/data/chunli5.bmp +0 -0
  65. data/data/chunli6.bmp +0 -0
  66. data/data/chunli7.bmp +0 -0
  67. data/data/chunli8.bmp +0 -0
  68. data/data/covid19.jpg +0 -0
  69. data/data/dsscaw-purp.png +0 -0
  70. data/data/eagles.png +0 -0
  71. data/data/fm6.mov +0 -0
  72. data/data/fonts.jpg +0 -0
  73. data/data/freebsd.png +0 -0
  74. data/data/lamepatents.jpg +0 -0
  75. data/data/megaman2.bmp +0 -0
  76. data/data/natasha-blur.png +0 -0
  77. data/data/natasha-blur.xcf +0 -0
  78. data/data/normal.png +0 -0
  79. data/data/normal.xcf +0 -0
  80. data/data/notcurses.png +0 -0
  81. data/data/notcursesIII.mov +0 -0
  82. data/data/onedot.png +0 -0
  83. data/data/samoa.avi +0 -0
  84. data/data/samoa.osp +296 -0
  85. data/data/spaceship.png +0 -0
  86. data/data/tetris-background.jpg +0 -0
  87. data/data/tetris-background.xcf +0 -0
  88. data/data/warmech.bmp +0 -0
  89. data/data/worldmap.png +0 -0
  90. data/exe/notcurses-ruby-testscript +57 -0
  91. data/ext/notcurses/extconf.rb +56 -17
  92. data/ext/notcurses/{notcurses_wrap.c → src/notcurses_wrap.c} +55459 -18930
  93. data/ext/notcurses/swig/notcurses.i +552 -0
  94. data/lib/notcurses/swig_mixins/struct_initializer.rb +25 -0
  95. data/lib/notcurses/swig_mixins/to_h.rb +22 -0
  96. data/lib/notcurses/version.rb +1 -1
  97. data/lib/notcurses.rb +34 -1
  98. metadata +98 -11
  99. data/ext/notcurses/Makefile +0 -269
  100. data/ext/notcurses/notcurses.i +0 -282
  101. data/ext/notcurses/notcurses_wrapper.h +0 -20
  102. /data/ext/notcurses/{ncplane_vprintf_aligned.c → src/ruby_ncplane_vprintf_aligned.c} +0 -0
  103. /data/ext/notcurses/{ncplane_vprintf_stained.c → src/ruby_ncplane_vprintf_stained.c} +0 -0
  104. /data/ext/notcurses/{ncplane_vprintf_yx.c → src/ruby_ncplane_vprintf_yx.c} +0 -0
  105. /data/ext/notcurses/{modified_ruby_std_wstring.i → swig/modified_ruby_std_wstring.i} +0 -0
@@ -0,0 +1,552 @@
1
+ %module notcurses
2
+
3
+ %feature("autodoc", "2");
4
+ %feature("kwargs", "1");
5
+
6
+ %constant unsigned long NANOSECS_IN_SEC = 1000000000ul;
7
+ %constant const char* PRIu64 = PRIu64;
8
+ %constant const char* PRId64 = PRId64;
9
+
10
+ // These empty defines are needed because SWIG seems to think compound macros
11
+ // are syntax errors.
12
+ %define __attribute__(x)
13
+ %enddef
14
+ %define __attribute(x)
15
+ %enddef
16
+ %define __declspec(x)
17
+ %enddef
18
+ %define __nonnull(x)
19
+ %enddef
20
+
21
+ %include <ruby/rubywstrings.swg>
22
+ %include <./modified_ruby_std_wstring.i>
23
+
24
+ %include <carrays.i>
25
+ %include <cdata.i>
26
+ %include <cmalloc.i>
27
+ %include <constraints.i>
28
+ %include <cpointer.i>
29
+ %include <cstring.i>
30
+ %include <inttypes.i>
31
+ %include <math.i>
32
+ %include <stdint.i>
33
+ %include <wchar.i>
34
+
35
+ %include <typemaps/attribute.swg>
36
+ %include <typemaps/carrays.swg>
37
+ %include <typemaps/cdata.swg>
38
+ %include <typemaps/cmalloc.swg>
39
+ %include <typemaps/cpointer.swg>
40
+ %include <typemaps/cstrings.swg>
41
+ %include <typemaps/cstring.swg>
42
+ %include <typemaps/cwstring.swg>
43
+ %include <typemaps/enumint.swg>
44
+ %include <typemaps/exception.swg>
45
+ %include <typemaps/factory.swg>
46
+ %include <typemaps/fragments.swg>
47
+ %include <typemaps/implicit.swg>
48
+ %include <typemaps/inoutlist.swg>
49
+ %include <typemaps/misctypes.swg>
50
+ %include <typemaps/primtypes.swg>
51
+ %include <typemaps/ptrtypes.swg>
52
+ %include <typemaps/strings.swg>
53
+ %include <typemaps/string.swg>
54
+ %include <typemaps/swigmacros.swg>
55
+ %include <typemaps/swigobject.swg>
56
+ %include <typemaps/swigtypemaps.swg>
57
+ %include <typemaps/swigtype.swg>
58
+ %include <typemaps/typemaps.swg>
59
+ %include <typemaps/valtypes.swg>
60
+ %include <typemaps/void.swg>
61
+ %include <typemaps/wstring.swg>
62
+
63
+ %include <ruby/ruby.swg>
64
+ %include <ruby/argcargv.i>
65
+ %include <ruby/rubyautodoc.swg>
66
+ %include <ruby/file.i>
67
+ %include <ruby/progargcargv.i>
68
+ %include <ruby/rubycomplex.swg>
69
+ %include <ruby/rubyprimtypes.swg>
70
+ %include <ruby/rubystrings.swg>
71
+ %include <ruby/timeval.i>
72
+ %include <ruby/typemaps.i>
73
+
74
+ // Put Helper Functions in this block
75
+ %{
76
+ #include <fcntl.h>
77
+ #include <unistd.h>
78
+ #include <locale.h>
79
+
80
+ // Helper function to determine file mode
81
+ static const char* get_file_mode(int fd) {
82
+ int flags = fcntl(fd, F_GETFL);
83
+ if (flags == -1) return "r"; // Default to read mode on error
84
+
85
+ int access_mode = flags & O_ACCMODE;
86
+ int append_flag = flags & O_APPEND;
87
+
88
+ if (access_mode == O_RDONLY) return "r";
89
+ if (access_mode == O_WRONLY) return append_flag ? "a" : "w";
90
+ if (access_mode == O_RDWR) return append_flag ? "a+" : "r+";
91
+
92
+ return "r";
93
+ }
94
+
95
+ // Helper function to call Ruby procs
96
+ static VALUE call_ruby_proc(VALUE proc, int argc, VALUE* argv) {
97
+ return rb_funcall2(proc, rb_intern("call"), argc, argv);
98
+ }
99
+ %}
100
+
101
+ // Package all function results in a hash
102
+ %typemap(out) SWIGTYPE*, SWIGTYPE& {
103
+ VALUE hash = rb_hash_new();
104
+ VALUE obj;
105
+
106
+ if (strcmp("$1_type", "void") == 0) {
107
+ obj = Qnil;
108
+ } else {
109
+ obj = SWIG_Ruby_NewPointerObj($1, $1_descriptor, $owner);
110
+ }
111
+
112
+ rb_hash_aset(hash, ID2SYM(rb_intern("return")), obj);
113
+ $result = hash;
114
+ }
115
+
116
+ %typemap(argout) SWIGTYPE*, SWIGTYPE & {
117
+ if ($result == Qnil) {
118
+ $result = rb_hash_new();
119
+ }
120
+ if (!RB_TYPE_P($result, T_HASH)) {
121
+ VALUE temp = rb_hash_new();
122
+ rb_hash_aset(temp, ID2SYM(rb_intern("return")), $result);
123
+ $result = temp;
124
+ }
125
+
126
+ swig_type_info *ty = SWIG_TypeQuery("$1_type");
127
+ if (!ty) ty = $1_descriptor;
128
+
129
+ VALUE obj = SWIG_NewPointerObj((void *)$1, ty, 0);
130
+ rb_hash_aset($result, ID2SYM(rb_intern("$1_name")), obj);
131
+ }
132
+
133
+ %typemap(out) char*, const char* {
134
+ VALUE hash = rb_hash_new();
135
+ VALUE obj;
136
+
137
+ if ($1 == NULL) {
138
+ obj = Qnil;
139
+ } else {
140
+ // Convert C string to Ruby string
141
+ obj = rb_str_new2($1);
142
+ }
143
+
144
+ rb_hash_aset(hash, ID2SYM(rb_intern("return")), obj);
145
+ $result = hash;
146
+ }
147
+
148
+ %typemap(argout) char*, const char* {
149
+ if ($result == Qnil) {
150
+ $result = rb_hash_new();
151
+ }
152
+ if (!RB_TYPE_P($result, T_HASH)) {
153
+ VALUE temp = rb_hash_new();
154
+ rb_hash_aset(temp, ID2SYM(rb_intern("return")), $result);
155
+ $result = temp;
156
+ }
157
+
158
+ VALUE obj = $1 ? rb_str_new2($1) : Qnil;
159
+ rb_hash_aset($result, ID2SYM(rb_intern("$1_name")), obj);
160
+ }
161
+
162
+ %typemap(out) wchar_t* {
163
+ VALUE hash = rb_hash_new();
164
+ VALUE obj;
165
+
166
+ if ($1 == NULL) {
167
+ obj = Qnil;
168
+ } else {
169
+ // Convert wchar_t* to UTF-8 encoded Ruby string
170
+ setlocale(LC_ALL, "");
171
+ size_t len = wcslen($1);
172
+ size_t utf8_len = wcstombs(NULL, $1, 0); // Get required buffer size
173
+ if (utf8_len != (size_t)-1) {
174
+ char *utf8_str = (char*)malloc(utf8_len + 1);
175
+ if (utf8_str) {
176
+ wcstombs(utf8_str, $1, utf8_len + 1);
177
+ obj = rb_str_new2(utf8_str);
178
+ rb_enc_associate(obj, rb_utf8_encoding());
179
+ free(utf8_str);
180
+ } else {
181
+ obj = Qnil; // Handle allocation failure
182
+ }
183
+ } else {
184
+ obj = Qnil; // Handle conversion failure
185
+ }
186
+ }
187
+
188
+ rb_hash_aset(hash, ID2SYM(rb_intern("return")), obj);
189
+ $result = hash;
190
+ }
191
+
192
+ %typemap(argout) wchar_t* {
193
+ if ($result == Qnil) {
194
+ $result = rb_hash_new();
195
+ }
196
+ if (!RB_TYPE_P($result, T_HASH)) {
197
+ VALUE temp = rb_hash_new();
198
+ rb_hash_aset(temp, ID2SYM(rb_intern("return")), $result);
199
+ $result = temp;
200
+ }
201
+
202
+ VALUE obj;
203
+ if ($1 == NULL) {
204
+ obj = Qnil;
205
+ } else {
206
+ // Convert wchar_t* to UTF-8 encoded Ruby string
207
+ setlocale(LC_ALL, "");
208
+ size_t utf8_len = wcstombs(NULL, $1, 0); // Get required buffer size
209
+ if (utf8_len != (size_t)-1) {
210
+ char *utf8_str = (char*)malloc(utf8_len + 1);
211
+ if (utf8_str) {
212
+ wcstombs(utf8_str, $1, utf8_len + 1);
213
+ obj = rb_str_new2(utf8_str);
214
+ rb_enc_associate(obj, rb_utf8_encoding());
215
+ free(utf8_str);
216
+ } else {
217
+ obj = Qnil; // Handle allocation failure
218
+ }
219
+ } else {
220
+ obj = Qnil; // Handle conversion failure
221
+ }
222
+ }
223
+
224
+ rb_hash_aset($result, ID2SYM(rb_intern("$1_name")), obj);
225
+ }
226
+
227
+ // Time is not on your side
228
+ %typemap(in) const struct timespec* {
229
+ if ($input == Qnil) {
230
+ $1 = NULL;
231
+ } else if (rb_obj_is_kind_of($input, rb_cTime)) {
232
+ static struct timespec ts;
233
+ VALUE seconds = rb_funcall($input, rb_intern("to_f"), 0);
234
+ ts.tv_sec = NUM2LONG(rb_funcall(seconds, rb_intern("floor"), 0));
235
+ ts.tv_nsec = NUM2LONG(rb_funcall(rb_funcall(rb_funcall(seconds, rb_intern("-"), 1, seconds), rb_intern("*"), 1, INT2NUM(1000000000)), rb_intern("floor"), 0));
236
+ $1 = &ts;
237
+ } else {
238
+ SWIG_exception(SWIG_TypeError, "Expected Time or nil");
239
+ }
240
+ }
241
+
242
+ // IO
243
+ %typemap(in) FILE* {
244
+ if ($input == Qnil) {
245
+ $1 = NULL;
246
+ } else if (rb_respond_to($input, rb_intern("fileno"))) {
247
+ int fd = NUM2INT(rb_funcall($input, rb_intern("fileno"), 0));
248
+ const char* mode = get_file_mode(fd);
249
+ $1 = fdopen(dup(fd), mode);
250
+ if (!$1) {
251
+ rb_raise(rb_eIOError, "Unable to get FILE* from Ruby IO object");
252
+ }
253
+ } else {
254
+ SWIG_exception(SWIG_TypeError, "Expected IO object or nil");
255
+ }
256
+ }
257
+
258
+ %typemap(out) FILE* {
259
+ if ($1 == NULL) {
260
+ $result = Qnil;
261
+ } else {
262
+ int fd = fileno($1);
263
+ if (fd == -1) {
264
+ rb_raise(rb_eIOError, "Invalid file descriptor");
265
+ }
266
+ VALUE io_class = rb_const_get(rb_cObject, rb_intern("IO"));
267
+ $result = rb_funcall(io_class, rb_intern("for_fd"), 1, INT2NUM(fd));
268
+ rb_funcall($result, rb_intern("binmode"), 0);
269
+ }
270
+ }
271
+
272
+ %typemap(argout) FILE** {
273
+ if (*$1 != NULL) {
274
+ int fd = fileno(*$1);
275
+ if (fd == -1) {
276
+ rb_raise(rb_eIOError, "Invalid file descriptor");
277
+ }
278
+ VALUE io_class = rb_const_get(rb_cObject, rb_intern("IO"));
279
+ VALUE io_obj = rb_funcall(io_class, rb_intern("for_fd"), 1, INT2NUM(fd));
280
+
281
+ // Set the mode of the IO object
282
+ const char* mode = "r"; // Default to read mode
283
+ if ((*$1)->_flags & _IO_NO_READS) {
284
+ if ((*$1)->_flags & _IO_APPEND) {
285
+ mode = "a";
286
+ } else {
287
+ mode = "w";
288
+ }
289
+ }
290
+ if (!((*$1)->_flags & _IO_NO_WRITES)) {
291
+ mode = (strcmp(mode, "r") == 0) ? "r+" : "w+";
292
+ }
293
+
294
+ // Set the mode
295
+ rb_funcall(io_obj, rb_intern("set_encoding"), 1, rb_str_new2(mode));
296
+
297
+ // Preserve the original encoding if possible
298
+ VALUE enc = rb_funcall(io_obj, rb_intern("internal_encoding"), 0);
299
+ if (enc == Qnil) {
300
+ enc = rb_funcall(io_obj, rb_intern("external_encoding"), 0);
301
+ }
302
+ if (enc != Qnil) {
303
+ rb_funcall(io_obj, rb_intern("set_encoding"), 1, enc);
304
+ } else {
305
+ // Fallback to binary mode if no encoding is detected
306
+ rb_funcall(io_obj, rb_intern("binmode"), 0);
307
+ }
308
+
309
+ rb_io_taint_check(io_obj);
310
+
311
+ $result = io_obj;
312
+ } else {
313
+ $result = Qnil;
314
+ }
315
+ }
316
+
317
+ %typemap(in) FILE** (FILE* tempfile = NULL) {
318
+ if ($input == Qnil) {
319
+ $1 = &tempfile;
320
+ } else if (rb_obj_is_kind_of($input, rb_cIO)) {
321
+ VALUE fileno = rb_funcall($input, rb_intern("fileno"), 0);
322
+ int fd = NUM2INT(fileno);
323
+ const char* mode = StringValueCStr(rb_funcall($input, rb_intern("mode"), 0));
324
+ tempfile = fdopen(dup(fd), mode);
325
+ if (!tempfile) {
326
+ rb_raise(rb_eIOError, "Could not create FILE* from Ruby IO object");
327
+ }
328
+ $1 = &tempfile;
329
+ } else {
330
+ SWIG_exception(SWIG_TypeError, "Expected IO object or nil");
331
+ }
332
+ }
333
+
334
+ %typemap(freearg) FILE** {
335
+ if (tempfile$argnum != NULL) {
336
+ fclose(tempfile$argnum);
337
+ }
338
+ }
339
+
340
+ // Integer Pointers
341
+ %typemap(in)
342
+ short*,
343
+ int*,
344
+ long*,
345
+ double*,
346
+ long long*,
347
+ int8_t*,
348
+ int16_t*,
349
+ int32_t*,
350
+ int64_t*,
351
+ unsigned short*,
352
+ unsigned int*,
353
+ unsigned long*,
354
+ unsigned long long*,
355
+ uint8_t*,
356
+ uint16_t*,
357
+ uint32_t*,
358
+ uint64_t* {
359
+
360
+ $1 = ($1_ltype) malloc(sizeof($*1_type));
361
+ if ($1 == NULL) {
362
+ SWIG_exception_fail(SWIG_MemoryError, "Failed to allocate memory");
363
+ }
364
+ switch(sizeof($*1_type)) {
365
+ case 1:
366
+ case 2:
367
+ case 4:
368
+ *$1 = ($*1_type) NUM2INT($input);
369
+ break;
370
+ case 8:
371
+ if (strcmp("$*1_type", "double") == 0) {
372
+ *$1 = ($*1_type) NUM2DBL($input);
373
+ } else {
374
+ *$1 = ($*1_type) NUM2LL($input);
375
+ }
376
+ break;
377
+ default:
378
+ SWIG_exception_fail(SWIG_TypeError, "Unsupported integer size");
379
+ }
380
+ }
381
+
382
+ %typemap(argout)
383
+ short*,
384
+ int*,
385
+ long*,
386
+ double*,
387
+ long long*,
388
+ int8_t*,
389
+ int16_t*,
390
+ int32_t*,
391
+ int64_t*,
392
+ size_t*,
393
+ unsigned short*,
394
+ unsigned int*,
395
+ unsigned long*,
396
+ unsigned long long*,
397
+ uint8_t*,
398
+ uint16_t*,
399
+ uint32_t*,
400
+ uint64_t* {
401
+
402
+ if ($1 != NULL) {
403
+ if ($result == Qnil) {
404
+ $result = rb_hash_new();
405
+ } else if (!RB_TYPE_P($result, T_HASH)) {
406
+ VALUE temp = rb_hash_new();
407
+ rb_hash_aset(temp, ID2SYM(rb_intern("return")), $result);
408
+ $result = temp;
409
+ }
410
+ VALUE converted_value;
411
+ switch(sizeof($*1_type)) {
412
+ case 1:
413
+ case 2:
414
+ case 4:
415
+ converted_value = INT2NUM(*$1);
416
+ break;
417
+ case 8:
418
+ if (strcmp("$*1_type", "double") == 0) {
419
+ converted_value = DBL2NUM(*$1);
420
+ } else {
421
+ converted_value = LL2NUM(*$1);
422
+ }
423
+ break;
424
+ default:
425
+ rb_raise(rb_eTypeError, "Unsupported integer size");
426
+ }
427
+ rb_hash_aset($result, ID2SYM(rb_intern("$1_name")), converted_value);
428
+ free($1);
429
+ }
430
+ }
431
+
432
+ // Callbacks
433
+ %typemap(in) fadecb, ncstreamcb, tabletcb, tabcb, ncfdplane_done_cb {
434
+ if (!NIL_P($input)) {
435
+ $1 = ($1_ltype)rb_proc_new((VALUE (*)(ANYARGS))call_ruby_proc, $input);
436
+ } else {
437
+ $1 = NULL;
438
+ }
439
+ }
440
+
441
+ // Stuff in the inline block is both written to the generated C code AND has
442
+ // swig wrappers generated for the functions.
443
+ %inline %{
444
+ #include <notcurses/ncport.h>
445
+ #include <notcurses/version.h>
446
+ #include <notcurses/nckeys.h>
447
+ #include <notcurses/ncseqs.h>
448
+ #include <notcurses/notcurses.h>
449
+ #include <notcurses/direct.h>
450
+
451
+
452
+ // Put fake function macros here.
453
+ // NCCHANNEL_INITIALIZER
454
+ uint32_t ncchannel_initializer(
455
+ uint32_t r,
456
+ uint32_t g,
457
+ uint32_t b
458
+ ) {
459
+ return ((r << 16u) + (g << 8u) + b + NC_BGDEFAULT_MASK);
460
+ }
461
+
462
+ // NCCHANNELS_INITIALIZER
463
+ uint64_t ncchannels_initializer(
464
+ uint32_t fr,
465
+ uint32_t fg,
466
+ uint32_t fb,
467
+ uint32_t br,
468
+ uint32_t bg,
469
+ uint32_t bb
470
+ ) {
471
+
472
+ uint64_t tmp_fg_chan = ((uint64_t)ncchannel_initializer(fr, fg, fb) << 32ull);
473
+ uint64_t tmp_bg_chan = ncchannel_initializer(br, bg, bb);
474
+
475
+ return tmp_fg_chan + tmp_bg_chan;
476
+ }
477
+
478
+
479
+ // NCMETRICFWIDTH
480
+ int ncmetricfwidth(const char* x, int cols) {
481
+ return (int)(strlen(x) - ncstrwidth(x, NULL, NULL) + cols);
482
+ }
483
+
484
+ // NCPREFIXFMT (note this macro expands to this as well as ", x")
485
+ int ncprefixfmt(const char* x) {
486
+ return (int)ncmetricfwidth(x, NCPREFIXCOLUMNS);
487
+ }
488
+
489
+ // NCIPREFIXFMT (note this macro expands to this as well as ", x")
490
+ int nciprefixfmt(const char* x) {
491
+ return (int)ncmetricfwidth(x, NCIPREFIXCOLUMNS);
492
+ }
493
+
494
+ // NCBPREFIXFMT (note this macro expands to this as well as ", x")
495
+ int ncbprefixfmt(const char* x) {
496
+ return (int)ncmetricfwidth(x, NCBPREFIXCOLUMNS);
497
+ }
498
+
499
+ // NCCELL_INITIALIZER
500
+ void nccell_initializer(nccell* cell, uint32_t c, uint16_t s, uint64_t chan) {
501
+ if (cell == NULL) return;
502
+ cell->gcluster = htole(c);
503
+ cell->gcluster_backstop = 0;
504
+ cell->width = (uint8_t)((wcwidth(c) < 0 || !c) ? 1 : wcwidth(c));
505
+ cell->stylemask = s;
506
+ cell->channels = chan;
507
+ }
508
+
509
+ // NCCELL_CHAR_INITIALIZER
510
+ void nccell_char_initializer(nccell* cell, uint32_t c) {
511
+ if (cell == NULL) return;
512
+ cell->gcluster = htole(c);
513
+ cell->gcluster_backstop = 0;
514
+ cell->width = (uint8_t)((wcwidth(c) < 0 || !c) ? 1 : wcwidth(c));
515
+ cell->stylemask = 0;
516
+ cell->channels = 0;
517
+ }
518
+
519
+ // NCCELL_TRIVIAL_INITIALIZER
520
+ void nccell_trivial_initializer(nccell* cell) {
521
+ if (cell == NULL) return;
522
+ cell->gcluster = 0;
523
+ cell->gcluster_backstop = 0;
524
+ cell->width = 1;
525
+ cell->stylemask = 0;
526
+ cell->channels = 0;
527
+ }
528
+
529
+ // Prototypes for functions that replace va_list arg functions, actual
530
+ // definitions are in .c files in ../src
531
+ int ruby_ncplane_vprintf_yx(struct ncplane* n, int y, int x, const char* format, VALUE rb_args);
532
+ int ruby_ncplane_vprintf_aligned(struct ncplane* n, int y, ncalign_e align, const char* format, VALUE rb_args);
533
+ int ruby_ncplane_vprintf_stained(struct ncplane* n, const char* format, VALUE rb_args);
534
+
535
+ int ruby_ncplane_vprintf(struct ncplane* n, const char* format, VALUE rb_args) {
536
+ return ruby_ncplane_vprintf_yx(n, -1, -1, format, rb_args);
537
+ }
538
+ %}
539
+
540
+ // Ignore problematic functions (va_list stuff)
541
+ %ignore ncplane_vprintf_yx;
542
+ %ignore ncplane_vprintf;
543
+ %ignore ncplane_vprintf_aligned;
544
+ %ignore ncplane_vprintf_stained;
545
+
546
+ %include <notcurses/ncport.h>
547
+ %include <notcurses/version.h>
548
+ %include <notcurses/nckeys.h>
549
+ %include <notcurses/ncseqs.h>
550
+ %include <notcurses/notcurses.h>
551
+ %include <notcurses/direct.h>
552
+
@@ -0,0 +1,25 @@
1
+ module Notcurses
2
+ module SwigMixins
3
+ module StructInitializer
4
+ def self.included(base)
5
+ base.class_eval do
6
+ alias_method :swig_initialize, :initialize
7
+
8
+ def initialize(**options)
9
+ swig_initialize
10
+
11
+ options.each do |k, v|
12
+ setter = "#{k}="
13
+
14
+ unless respond_to?(setter)
15
+ raise ArgumentError, "Unknown attribute: #{k}"
16
+ end
17
+
18
+ send(setter, v)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # There might be a better way, but this works.
2
+ module Notcurses
3
+ module SwigMixins
4
+ module ToH
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def to_h
8
+ hash = {}
9
+ meffids = self.class.instance_methods(false).select{|m| m !~ /=$/}
10
+
11
+ meffids.each do |m|
12
+ next if (m == :to_h || m =~ /=$/)
13
+ hash[m] = send(m)[:return] if method(m).arity < 1
14
+ end
15
+
16
+ hash
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Notcurses
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
data/lib/notcurses.rb CHANGED
@@ -1,4 +1,37 @@
1
1
  # frozen_string_literal: true
2
+ #
3
+ # Temporarily suppress warnings to kill allocator warnings, should be fixed
4
+ # in SWIG 4.2
5
+ $VERBOSE = nil
6
+ require 'notcurses.so'
2
7
 
3
8
  require_relative 'notcurses/version'
4
- require_relative 'notcurses.so'
9
+ require_relative 'notcurses/swig_mixins/struct_initializer'
10
+ require_relative 'notcurses/swig_mixins/to_h'
11
+
12
+ module Notcurses
13
+ # No matter how hard I tried I could not get SWIG to do this for me.
14
+ class << self
15
+ alias_method :ncplane_vprintf_yx, :ruby_ncplane_vprintf_yx
16
+ alias_method :ncplane_vprintf, :ruby_ncplane_vprintf
17
+ alias_method :ncplane_vprintf_aligned, :ruby_ncplane_vprintf_aligned
18
+ alias_method :ncplane_vprintf_stained, :ruby_ncplane_vprintf_stained
19
+ end
20
+
21
+ # This is a stub, couldn't find an easy way to figure this out looking at
22
+ # constants and methods etc. There is an instance variable but I'd have to
23
+ # instantiate it to get it...
24
+ def self.swig_generated_class?(klass)
25
+ true
26
+ end
27
+
28
+ # "Mixin' the Swiiiggssss" -- Pauly Shore
29
+ constants.each do |const_name|
30
+ const = const_get(const_name)
31
+ if const.is_a?(Class) && swig_generated_class?(const)
32
+ const.include(SwigMixins::StructInitializer)
33
+ const.include(SwigMixins::ToH)
34
+ end
35
+ end
36
+ end
37
+