curses 1.4.7 → 1.5.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0170d14a883cec80159b24d85a55741eb721b1863f5eb1d67aea90cf2f54d28c
4
- data.tar.gz: 6abb516cc2e6d83eff1c63c2b2f0c27e0e621e759846ba5bf6d5c27beca09a89
3
+ metadata.gz: b7821de0b5980058b3b4adb34b39ba47e875102ce604bcff147583280af163d0
4
+ data.tar.gz: c8276542d1753d2e6d75097410b4bf13d75e37024c12fb8906a3b9f2b34e4c08
5
5
  SHA512:
6
- metadata.gz: d9b13bba5b82c8d2e0a0628698c5e87ac3d9f258f57df8323ecf4157e2704b278fb47103ad112b25b7d780b5ea5fe6cffa3bea9e629a501f4b09d88e2eba96f3
7
- data.tar.gz: be30e6050811c9091a7765b0a4aa3f349a9e498edae1cdbf90b4ae34b29c8881a4a5c508a449aeaba8132a5cf0b207b731fe1960bc5dd8b3335837197c5c23cb
6
+ metadata.gz: bcb0b093de4c2716b505d7905263ed808601d599fa0038dd300365f77280ec730636b92697a8a3ca515ebe21ed8979209ce4c9852c956755e414788b21b5f86a
7
+ data.tar.gz: 1cd648fb5c3ec64a3fb221f42e4048f5edd096fa5cba801faaf247fc153a77598948a29b62026141802f5e07126857f4b9291569f1b51c1c72d2efdcf13674d3
@@ -24,23 +24,23 @@ jobs:
24
24
  steps:
25
25
  # Set up
26
26
  - name: Harden Runner
27
- uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
27
+ uses: step-security/harden-runner@v2
28
28
  with:
29
29
  egress-policy: audit
30
30
 
31
- - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
31
+ - uses: actions/checkout@v4
32
32
  with:
33
33
  submodules: true
34
34
 
35
35
  - name: Set up Ruby
36
- uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
36
+ uses: ruby/setup-ruby@v1
37
37
  with:
38
38
  bundler-cache: true
39
39
  ruby-version: ruby
40
40
 
41
41
  # Release
42
42
  - name: Publish to RubyGems
43
- uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1
43
+ uses: rubygems/release-gem@v1
44
44
 
45
45
  - name: Create GitHub release
46
46
  run: |
data/README.md CHANGED
@@ -46,7 +46,13 @@ _with `/usr/local/opt/ncurses` the path where homebrew installed ncurses on your
46
46
 
47
47
  ## Documentation
48
48
 
49
- See [https://www.rubydoc.info/gems/curses](https://www.rubydoc.info/gems/curses).
49
+ Type the following command, and see `[rdoc]` of curses:
50
+
51
+ > gem server -l
52
+
53
+ ## Limitations
54
+
55
+ * curses.gem doesn't support more than 256 color pairs. See https://reversed.top/2019-02-05/more-than-256-curses-color-pairs/ for details.
50
56
 
51
57
  ## Developers
52
58
 
@@ -55,6 +61,7 @@ After checking out the repo, run `bundle install` to install dependencies.
55
61
  To compile the extension library, run `bundle exec rake compile`.
56
62
 
57
63
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `curses.gemspec`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
64
+
58
65
  ## License
59
66
 
60
67
  curses is released under the Ruby and 2-clause BSD licenses. See COPYING for
data/curses.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new { |s|
2
2
  s.name = "curses"
3
- s.version = "1.4.7"
3
+ s.version = "1.5.0"
4
4
  s.author = ["Shugo Maeda", 'Eric Hodel']
5
5
  s.email = ["shugo@ruby-lang.org", 'drbrain@segment7.net']
6
6
  s.homepage = "https://github.com/ruby/curses"
@@ -9,7 +9,7 @@ Gem::Specification.new { |s|
9
9
  s.files = `git ls-files --recurse-submodules -z`.split("\x0")
10
10
  s.extensions = ["ext/curses/extconf.rb"]
11
11
  s.require_path = "lib"
12
- s.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
12
+ s.required_ruby_version = Gem::Requirement.new('>= 3.0')
13
13
  s.licenses = ['Ruby', 'BSD-2-Clause']
14
14
  s.add_development_dependency 'bundler'
15
15
  s.add_development_dependency 'rake'
data/ext/curses/curses.c CHANGED
@@ -98,8 +98,13 @@ rb_obj2chtype_inline(VALUE x)
98
98
 
99
99
  static VALUE mCurses;
100
100
  static VALUE mKey;
101
+ #ifdef HAVE_NEWTERM
102
+ static VALUE cScreen;
103
+ #endif
101
104
  static VALUE cWindow;
105
+ #ifdef HAVE_NEWPAD
102
106
  static VALUE cPad;
107
+ #endif
103
108
  #ifdef USE_MOUSE
104
109
  static VALUE cMouseEvent;
105
110
  #endif
@@ -220,6 +225,7 @@ check_curses_error(int error)
220
225
 
221
226
  struct windata {
222
227
  WINDOW *window;
228
+ int is_stdscr;
223
229
  };
224
230
 
225
231
  static VALUE window_attroff(VALUE obj, VALUE attrs);
@@ -242,7 +248,7 @@ static void
242
248
  window_free(void *p)
243
249
  {
244
250
  struct windata *winp = p;
245
- if (winp->window && winp->window != stdscr) delwin(winp->window);
251
+ if (winp->window && !winp->is_stdscr) delwin(winp->window);
246
252
  winp->window = 0;
247
253
  xfree(winp);
248
254
  }
@@ -263,7 +269,7 @@ static const rb_data_type_t windata_type = {
263
269
  };
264
270
 
265
271
  static VALUE
266
- prep_window(VALUE class, WINDOW *window)
272
+ prep_window(VALUE class, WINDOW *window, int is_stdscr)
267
273
  {
268
274
  VALUE obj;
269
275
  struct windata *winp;
@@ -275,6 +281,7 @@ prep_window(VALUE class, WINDOW *window)
275
281
  obj = rb_obj_alloc(class);
276
282
  TypedData_Get_Struct(obj, struct windata, &windata_type, winp);
277
283
  winp->window = window;
284
+ winp->is_stdscr = is_stdscr;
278
285
 
279
286
  return obj;
280
287
  }
@@ -311,7 +318,7 @@ curses_init_screen(VALUE self)
311
318
  }
312
319
  rb_set_end_proc(curses_finalize, 0);
313
320
  clear();
314
- rb_stdscr = prep_window(cWindow, stdscr);
321
+ rb_stdscr = prep_window(cWindow, stdscr, 1);
315
322
  return rb_stdscr;
316
323
  }
317
324
 
@@ -1443,7 +1450,7 @@ curses_pair_content(VALUE obj, VALUE pair)
1443
1450
  static VALUE
1444
1451
  curses_color_pair(VALUE obj, VALUE attrs)
1445
1452
  {
1446
- return INT2FIX(COLOR_PAIR(NUM2INT(attrs)));
1453
+ return CHTYPE2NUM(COLOR_PAIR(NUM2CHTYPE(attrs)));
1447
1454
  }
1448
1455
 
1449
1456
  /*
@@ -1456,7 +1463,7 @@ static VALUE
1456
1463
  curses_pair_number(VALUE obj, VALUE attrs)
1457
1464
  {
1458
1465
  curses_stdscr();
1459
- return INT2FIX(PAIR_NUMBER(NUM2LONG(attrs)));
1466
+ return INT2FIX(PAIR_NUMBER(NUM2CHTYPE(attrs)));
1460
1467
  }
1461
1468
  #endif /* USE_COLOR */
1462
1469
 
@@ -1683,6 +1690,121 @@ curses_reset_prog_mode(VALUE obj)
1683
1690
  #define curses_reset_prog_mode rb_f_notimplement
1684
1691
  #endif
1685
1692
 
1693
+ /*-------------------------- class Screen --------------------------*/
1694
+
1695
+ #ifdef HAVE_NEWTERM
1696
+
1697
+ struct screendata {
1698
+ SCREEN *screen;
1699
+ VALUE stdscr;
1700
+ };
1701
+
1702
+ NORETURN(static void no_screen(void));
1703
+ static void
1704
+ no_screen(void)
1705
+ {
1706
+ rb_raise(rb_eRuntimeError, "no screen");
1707
+ }
1708
+
1709
+ #define GetSCREEN(obj, screenp) do {\
1710
+ TypedData_Get_Struct((obj), struct screendata, &screendata_type, (screenp));\
1711
+ if ((screenp)->screen == 0) no_screen();\
1712
+ } while (0)
1713
+
1714
+ static void
1715
+ screen_gc_mark(void *p)
1716
+ {
1717
+ struct screendata *screenp = p;
1718
+
1719
+ rb_gc_mark(screenp->stdscr);
1720
+ }
1721
+
1722
+ static void
1723
+ screen_free(void *p)
1724
+ {
1725
+ struct screendata *screenp = p;
1726
+ if (screenp->screen) delscreen(screenp->screen);
1727
+ screenp->screen = 0;
1728
+ xfree(screenp);
1729
+ }
1730
+
1731
+ static size_t
1732
+ screen_memsize(const void *p)
1733
+ {
1734
+ const struct screendata *screenp = p;
1735
+ size_t size = sizeof(*screenp);
1736
+ if (!screenp) return 0;
1737
+ if (screenp->screen) size += CURSES_SIZEOF_SCREEN;
1738
+ return size;
1739
+ }
1740
+
1741
+ static const rb_data_type_t screendata_type = {
1742
+ "screendata",
1743
+ {screen_gc_mark, screen_free, screen_memsize,}
1744
+ };
1745
+
1746
+ /* returns a Curses::Screen object */
1747
+ static VALUE
1748
+ screen_s_allocate(VALUE class)
1749
+ {
1750
+ struct screendata *screenp;
1751
+
1752
+ return TypedData_Make_Struct(class, struct screendata, &screendata_type, screenp);
1753
+ }
1754
+
1755
+ /*
1756
+ * Document-method: Curses::Screen.new
1757
+ * call-seq: new(outf, inf, type=nil)
1758
+ *
1759
+ * Construct a new Curses::Screen.
1760
+ */
1761
+ static VALUE
1762
+ screen_initialize(int argc, VALUE *argv, VALUE obj)
1763
+ {
1764
+ VALUE outf, inf, type;
1765
+ struct screendata *screenp;
1766
+ rb_io_t *outfptr, *infptr;
1767
+
1768
+ rb_scan_args(argc, argv, "21", &outf, &inf, &type);
1769
+ TypedData_Get_Struct(obj, struct screendata, &screendata_type, screenp);
1770
+ if (screenp->screen) delscreen(screenp->screen);
1771
+ Check_Type(outf, T_FILE);
1772
+ RB_IO_POINTER(outf, outfptr);
1773
+ rb_io_check_writable(outfptr);
1774
+ Check_Type(inf, T_FILE);
1775
+ RB_IO_POINTER(inf, infptr);
1776
+ rb_io_check_readable(infptr);
1777
+ screenp->screen = newterm(NIL_P(type) ? NULL : StringValueCStr(type),
1778
+ rb_io_stdio_file(outfptr),
1779
+ rb_io_stdio_file(infptr));
1780
+ screenp->stdscr = Qnil;
1781
+
1782
+ return obj;
1783
+ }
1784
+
1785
+ /*
1786
+ * Document-method: Curses::Screen.set_term
1787
+ * call-seq: set_term
1788
+ *
1789
+ * Set the current terminal.
1790
+ */
1791
+ static VALUE
1792
+ screen_set_term(VALUE obj)
1793
+ {
1794
+ struct screendata *screenp;
1795
+
1796
+ GetSCREEN(obj, screenp);
1797
+ set_term(screenp->screen);
1798
+ if (NIL_P(screenp->stdscr)) {
1799
+ screenp->stdscr = prep_window(cWindow, stdscr, 1);
1800
+ }
1801
+ rb_stdscr = screenp->stdscr;
1802
+
1803
+ return Qnil;
1804
+ }
1805
+
1806
+ #endif /* HAVE_NEWTERM */
1807
+
1686
1808
  /*-------------------------- class Window --------------------------*/
1687
1809
 
1688
1810
  /* returns a Curses::Window object */
@@ -1743,7 +1865,7 @@ window_subwin(VALUE obj, VALUE height, VALUE width, VALUE top, VALUE left)
1743
1865
  l = NUM2INT(left);
1744
1866
  GetWINDOW(obj, winp);
1745
1867
  window = subwin(winp->window, h, w, t, l);
1746
- win = prep_window(rb_obj_class(obj), window);
1868
+ win = prep_window(rb_obj_class(obj), window, 0);
1747
1869
 
1748
1870
  return win;
1749
1871
  }
@@ -1772,7 +1894,7 @@ window_derwin(VALUE obj, VALUE height, VALUE width, VALUE top, VALUE left)
1772
1894
  l = NUM2INT(left);
1773
1895
  GetWINDOW(obj, winp);
1774
1896
  window = derwin(winp->window, h, w, t, l);
1775
- win = prep_window(rb_obj_class(obj), window);
1897
+ win = prep_window(rb_obj_class(obj), window, 0);
1776
1898
 
1777
1899
  return win;
1778
1900
  }
@@ -2672,7 +2794,7 @@ window_attroff(VALUE obj, VALUE attrs)
2672
2794
  struct windata *winp;
2673
2795
 
2674
2796
  GetWINDOW(obj,winp);
2675
- return INT2FIX(wattroff(winp->window,NUM2INT(attrs)));
2797
+ return INT2FIX(wattroff(winp->window,NUM2CHTYPE(attrs)));
2676
2798
  #else
2677
2799
  return Qtrue;
2678
2800
  #endif
@@ -2695,10 +2817,10 @@ window_attron(VALUE obj, VALUE attrs)
2695
2817
  VALUE val;
2696
2818
 
2697
2819
  GetWINDOW(obj,winp);
2698
- val = INT2FIX(wattron(winp->window,NUM2INT(attrs)));
2820
+ val = INT2FIX(wattron(winp->window,NUM2CHTYPE(attrs)));
2699
2821
  if (rb_block_given_p()) {
2700
2822
  rb_yield(val);
2701
- wattroff(winp->window,NUM2INT(attrs));
2823
+ wattroff(winp->window,NUM2CHTYPE(attrs));
2702
2824
  return val;
2703
2825
  }
2704
2826
  else{
@@ -2742,7 +2864,7 @@ window_attrset(VALUE obj, VALUE attrs)
2742
2864
  struct windata *winp;
2743
2865
 
2744
2866
  GetWINDOW(obj,winp);
2745
- return INT2FIX(wattrset(winp->window,NUM2INT(attrs)));
2867
+ return INT2FIX(wattrset(winp->window,NUM2CHTYPE(attrs)));
2746
2868
  #else
2747
2869
  return Qtrue;
2748
2870
  #endif
@@ -2810,6 +2932,31 @@ window_getbkgd(VALUE obj)
2810
2932
  #endif
2811
2933
  }
2812
2934
 
2935
+ /*
2936
+ * Document-method: Curses::Window.chgat
2937
+ * call-seq: chgat(n, attrs)
2938
+ *
2939
+ * Changes the attributes of a given number of characters starting at
2940
+ * the current cursor location.
2941
+ */
2942
+ static VALUE
2943
+ window_chgat(VALUE obj, VALUE n, VALUE attrs)
2944
+ {
2945
+ #ifdef HAVE_WCHGAT
2946
+ chtype a = NUM2CHTYPE(attrs);
2947
+ attr_t attr;
2948
+ short pair;
2949
+ struct windata *winp;
2950
+
2951
+ GetWINDOW(obj,winp);
2952
+ attr = a & A_ATTRIBUTES;
2953
+ pair = PAIR_NUMBER(attr);
2954
+ return (wchgat(winp->window, NUM2INT(n), attr, pair, NULL) == OK) ? Qtrue : Qfalse;
2955
+ #else
2956
+ return Qnil;
2957
+ #endif
2958
+ }
2959
+
2813
2960
  /*
2814
2961
  * Document-method: Curses::Window.resize
2815
2962
  * call-seq: resize(lines, cols)
@@ -2986,7 +3133,7 @@ pad_subpad(VALUE obj, VALUE height, VALUE width, VALUE begin_x, VALUE begin_y)
2986
3133
  y = NUM2INT(begin_y);
2987
3134
  GetWINDOW(obj, padp);
2988
3135
  sub_pad = subpad(padp->window, h, w, x, y);
2989
- pad = prep_window(rb_obj_class(obj), sub_pad);
3136
+ pad = prep_window(rb_obj_class(obj), sub_pad, 0);
2990
3137
 
2991
3138
  return pad;
2992
3139
  }
@@ -4973,6 +5120,34 @@ Init_curses(void)
4973
5120
  rb_define_const(mCurses, "VERSION", version);
4974
5121
  }
4975
5122
 
5123
+ #ifdef HAVE_NEWTERM
5124
+ /*
5125
+ * Document-class: Curses::Screen
5126
+ *
5127
+ * == Description
5128
+ *
5129
+ * A Screen represents a terminal.
5130
+ * A program that outputs to more than one terminal should create a Screen
5131
+ * for each terminal instead of calling Curses.init_screen.
5132
+ *
5133
+ * == Usage
5134
+ *
5135
+ * require "curses"
5136
+ *
5137
+ * screen = Screen.new(STDOUT, STDIN, "xterm")
5138
+ * screen.set_term
5139
+ *
5140
+ * Curses.addstr("Hit any key")
5141
+ * Curses.refresh
5142
+ * Curses.getch
5143
+ * Curses.close_screen
5144
+ */
5145
+ cScreen = rb_define_class_under(mCurses, "Screen", rb_cObject);
5146
+ rb_define_alloc_func(cScreen, screen_s_allocate);
5147
+ rb_define_method(cScreen, "initialize", screen_initialize, -1);
5148
+ rb_define_method(cScreen, "set_term", screen_set_term, 0);
5149
+ #endif
5150
+
4976
5151
  /*
4977
5152
  * Document-class: Curses::Window
4978
5153
  *
@@ -5064,6 +5239,7 @@ Init_curses(void)
5064
5239
  rb_define_method(cWindow, "bkgdset", window_bkgdset, 1);
5065
5240
  rb_define_method(cWindow, "bkgd", window_bkgd, 1);
5066
5241
  rb_define_method(cWindow, "getbkgd", window_getbkgd, 0);
5242
+ rb_define_method(cWindow, "chgat", window_chgat, 2);
5067
5243
 
5068
5244
  rb_define_method(cWindow, "nodelay=", window_nodelay, 1);
5069
5245
  rb_define_method(cWindow, "timeout=", window_timeout, 1);
@@ -121,7 +121,8 @@ if header_library
121
121
  touchwin untouchwin wtouchln is_linetouched is_wintouched
122
122
  def_prog_mode reset_prog_mode timeout wtimeout nodelay
123
123
  init_color wcolor_set use_default_colors assume_default_colors
124
- newpad unget_wch get_wch wget_wch PDC_get_key_modifiers)
124
+ newpad unget_wch get_wch wget_wch PDC_get_key_modifiers
125
+ chgat wchgat newterm)
125
126
  have_func(f) || (have_macro(f, curses) && $defs.push(format("-DHAVE_%s", f.upcase)))
126
127
  end
127
128
  convertible_int('chtype', [["#undef MOUSE_MOVED\n"]]+curses) or abort
@@ -220,7 +221,7 @@ if header_library
220
221
  have_func("form_driver_w")
221
222
  end
222
223
 
223
- ["WINDOW", "MEVENT", "ITEM", "MENU", "FIELD", "FORM"].each do |type|
224
+ ["WINDOW", "MEVENT", "ITEM", "MENU", "FIELD", "FORM", "SCREEN"].each do |type|
224
225
  checking_for("sizeof(#{type}) is available") {
225
226
  if try_compile(<<EOF, Shellwords.join($defs))
226
227
  #if defined(HAVE_PDCURSES_H)
data/lib/curses.rb CHANGED
@@ -87,3 +87,10 @@ if defined?(Curses::Menu)
87
87
  end
88
88
  end
89
89
 
90
+ module Curses
91
+ module_function
92
+
93
+ def chgat(...)
94
+ Curses.stdscr.chgat(...)
95
+ end
96
+ end
data/sample/attr_demo.rb CHANGED
@@ -26,7 +26,9 @@ begin
26
26
  addstr([*('a'..'z'), *('0'..'9')].join + "\n")
27
27
  }
28
28
  getch
29
-
29
+ setpos(0, 0)
30
+ chgat(6, A_UNDERLINE)
31
+ getch
30
32
  ensure
31
33
  close_screen
32
- end
34
+ end
data/sample/screen.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "curses"
2
+
3
+ screen = Curses::Screen.new(STDOUT, STDIN, "xterm")
4
+ screen.set_term
5
+
6
+ Curses.addstr("Hit any key")
7
+ Curses.refresh
8
+ Curses.getch
9
+ Curses.close_screen
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curses
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.7
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda
8
8
  - Eric Hodel
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-10-22 00:00:00.000000000 Z
11
+ date: 2025-04-10 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -39,7 +38,6 @@ dependencies:
39
38
  - - ">="
40
39
  - !ruby/object:Gem::Version
41
40
  version: '0'
42
- description:
43
41
  email:
44
42
  - shugo@ruby-lang.org
45
43
  - drbrain@segment7.net
@@ -75,6 +73,7 @@ files:
75
73
  - sample/mouse.rb
76
74
  - sample/mouse_move.rb
77
75
  - sample/rain.rb
76
+ - sample/screen.rb
78
77
  - sample/view.rb
79
78
  - sample/view2.rb
80
79
  - vendor/PDCurses/.gitignore
@@ -326,7 +325,6 @@ licenses:
326
325
  - Ruby
327
326
  - BSD-2-Clause
328
327
  metadata: {}
329
- post_install_message:
330
328
  rdoc_options: []
331
329
  require_paths:
332
330
  - lib
@@ -334,15 +332,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
334
332
  requirements:
335
333
  - - ">="
336
334
  - !ruby/object:Gem::Version
337
- version: 2.6.0
335
+ version: '3.0'
338
336
  required_rubygems_version: !ruby/object:Gem::Requirement
339
337
  requirements:
340
338
  - - ">="
341
339
  - !ruby/object:Gem::Version
342
340
  version: '0'
343
341
  requirements: []
344
- rubygems_version: 3.5.9
345
- signing_key:
342
+ rubygems_version: 3.6.2
346
343
  specification_version: 4
347
344
  summary: A Ruby binding for curses, ncurses, and PDCurses. curses is an extension
348
345
  library for text UI applications. Formerly part of the Ruby standard library, [curses