diff options
author | Andrew Shadura <andrewsh@debian.org> | 2018-04-24 17:35:40 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2018-04-24 17:35:40 +0200 |
commit | 8df190991a04fe364f82fb8fcb25f93590f33610 (patch) | |
tree | cdf25d35ed899ffed0dbd87e2733f3f756969f9d | |
parent | 6017f14977999fbfed94d3d4474165724ec0412a (diff) | |
parent | c5965c88d9cbc3d900b9fb78fa6025382523e8ca (diff) |
Updated version 1.2.4 from 'upstream/1.2.4'
with Debian dir c1341b981b2223cdfa64cab62dd5617ce9f01697
-rw-r--r-- | .gitignore | 15 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | .travis.yml | 13 | ||||
-rw-r--r-- | Gemfile | 4 | ||||
-rw-r--r-- | History.md | 90 | ||||
-rw-r--r-- | Manifest.txt | 16 | ||||
-rw-r--r-- | README.md | 66 | ||||
-rw-r--r-- | Rakefile | 95 | ||||
-rw-r--r-- | appveyor.yml | 16 | ||||
-rw-r--r-- | checksums.yaml.gz.sig | bin | 256 -> 0 bytes | |||
-rw-r--r-- | curses.gemspec | 18 | ||||
-rw-r--r-- | data.tar.gz.sig | bin | 256 -> 0 bytes | |||
-rw-r--r-- | ext/curses/curses.c | 600 | ||||
-rw-r--r-- | ext/curses/extconf.rb | 28 | ||||
-rw-r--r-- | lib/curses.rb | 24 | ||||
-rw-r--r-- | metadata.gz.sig | 1 | ||||
-rwxr-xr-x | sample/hello.rb | 27 | ||||
-rwxr-xr-x | sample/mouse.rb | 32 | ||||
-rwxr-xr-x | sample/rain.rb | 96 | ||||
-rwxr-xr-x | sample/view.rb | 61 | ||||
-rwxr-xr-x | sample/view2.rb | 85 |
21 files changed, 1024 insertions, 266 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c09e7b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.rbc +*.swp +/TAGS +/doc +/lib/curses.bundle +/lib/curses.so +/lib/curses.dll +/pkg +/tmp +/Gemfile.lock +/vendor/x86-mingw32 +/vendor/x64-mingw32 +/vendor/x64-mswin64* +/ext/curses/Makefile +.ruby-version diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0f5a59b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/PDCurses"] + path = vendor/PDCurses + url = https://github.com/Bill-Gray/PDCurses.git diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f2957f8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +--- +language: ruby +notifications: + email: + recipients: + - drbrain@segment7.net + - shugo@ruby-lang.org +rvm: + - 2.2.7 + - 2.3.4 + - 2.4.1 + - ruby-head +script: rake compile @@ -0,0 +1,4 @@ +# frozen_string_literal: true +source "https://rubygems.org" + +gemspec @@ -1,3 +1,93 @@ +### 1.2.4 / 2017-09-13 + +New features: + +* Update PDCurses. + +Bug fixes: + +* Fix the path of pdcurses.dll for i386-mingw. (Issue #36) + +Documentation: + +* Include reference to ncurses dependency. Pull request #34 by qume. + +### 1.2.3 / 2017-07-03 + +Bug fixes: + +* Fixes for mswin. Pull requests #30, #31, #32 and #33 by unak. + +### 1.2.2 / 2017-04-22 + +New features: + +* Add Curses.get_key_modifiers, Curses.return_key_modifiers, and + Curses.save_key_modifiers. +* Support mswin native build. Pull request #29 by usa. + +### 1.2.1 / 2017-03-27 + +New features: + +* Add touch, untouch, touched?, touch_line, and line_touched?. + +Bug fixes: + +* Fix Pad#subpad to use subpad(3). (Issue #23) +* Fix build issues on macOS. Pull requests #24, #25, #26, #27 and #28 by nobu. + +### 1.2.0 / 2017-02-19 + +New features: + +* Add Curses.assume_default_colors. + +Bug fixes: + +* Curses.unget_char should use String#ord even if unget_wch() is not available. +* The default value of keyboard_encoding should be ASCII-8BIT if get_wch() is + not available. +* NUM2ULONG() should be used in Window#bkgd etc. + +### 1.1.3 / 2017-02-08 + +Bug fixes: + +* Update PDCurses to handle extended keys. + +### 1.1.2 / 2017-02-06 + +Bug fixes: + +* Use the left-alt-fix branch of https://github.com/shugo/PDCurses.git to get + ALT + < etc. + +### 1.1.1 / 2017-01-25 + +Bug fixes: + +* Add -DPDC_WIDE to CPPFLAGS when compiling with PDCurses. + +### 1.1.0 / 2017-01-24 + +New features: + +* Use bundler instead of hoe. Pull request #18 by hsbt. +* Enable appveyor. Pull request #19 by hsbt. +* Add badges for build status to README.md. Pull request #20 by hsbt. +* Add Curses.erase and Curses::Window.erase. +* Add Curses::Window.redraw. +* Add Curses.unget_char, Curses.get_char, and Curses::Window.get_char for + multibyte characters. +* Add Curses.keyboard_encoding and Curses.terminal_encoding. +* Support cross compilation for mingw32. + +Bug fixes: + +* Fix error in attron/attroff documentation. Pull request #14 by stomar. +* Improve code samples. Pull request #15 by stomar. + ### 1.0.2 / 2016-03-15 Bug fixes: diff --git a/Manifest.txt b/Manifest.txt deleted file mode 100644 index fff049d..0000000 --- a/Manifest.txt +++ /dev/null @@ -1,16 +0,0 @@ -BSDL -COPYING -History.md -Manifest.txt -README.md -Rakefile -curses.gemspec -ext/curses/curses.c -ext/curses/depend -ext/curses/extconf.rb -lib/curses.rb -sample/hello.rb -sample/mouse.rb -sample/rain.rb -sample/view.rb -sample/view2.rb @@ -1,5 +1,9 @@ # curses +[![Gem Version](https://badge.fury.io/rb/curses.svg)](https://badge.fury.io/rb/curses) +[![Build Status](https://travis-ci.org/ruby/curses.svg?branch=master)](https://travis-ci.org/ruby/curses) +[![Build status](https://ci.appveyor.com/api/projects/status/kdvksgjo4fyd3c4m/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/curses/branch/master) + * https://github.com/ruby/curses * https://github.com/ruby/curses/issues @@ -14,20 +18,74 @@ with the release of Ruby 2.1.0. (see [ruby/ruby@9c5b2fd][2]) ## Install $ gem install curses + +Requires ncurses or ncursesw (with wide character support). +On Debian based distributions, you can install it with apt: + + $ apt install libncurses5-dev + +Or + + $ apt install libncursesw5-dev ## Developers -After checking out the source, run: +After checking out the repo, run `bundle install` to install dependencies. + +To compile the extension library, run `bundle exec rake compile`. + +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). + +### Cross compilation for Windows on Debian GNU/Linux based platforms + +1. Install development environment fo 32- and 64-bit Windows. + + ``` + $ sudo apt-get install mingw-w64 + ``` + +2. Install rake-compiler. - $ rake newb + ``` + $ gem install rake-compiler + ``` -This task will install any missing dependencies, run the tests/specs, -and generate the RDoc. +3. Compile multiple versions of Ruby. + + ``` + $ rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.2.6 + $ rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.3.3 + $ rake-compiler cross-ruby HOST=i686-w64-mingw32 VERSION=2.4.0 + $ rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.2.6 + $ rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.3.3 + $ rake-compiler cross-ruby HOST=x86_64-w64-mingw32 VERSION=2.4.0 + ``` + +3. Compile PDCurses. + + ``` + $ rake build:pdcurses + ``` + +5. Compile curses.gem. + + ``` + $ rake RUBY_CC_VERSION=2.3.3:2.4.0 cross clean compile native gem + ``` + +Binary gems are generated in pkg/. ## License curses is released under the Ruby and 2-clause BSD licenses. See COPYING for details. +Binary gems for mingw32 include a forked version of PDCurses, which is in +the public domain: + + https://github.com/Bill-Gray/PDCurses + +The version for Win32 console mode in the win32 subdirectory is used. + [1]: https://bugs.ruby-lang.org/issues/8584 [2]: https://github.com/ruby/ruby/commit/9c5b2fd8aa0fd343ad094d47a638cfd3f6ae0a81 @@ -1,41 +1,84 @@ -# -*- ruby -*- +require "bundler" + +Bundler::GemHelper.install_tasks -require 'rubygems' -require 'hoe' begin require 'rake/extensiontask' rescue LoadError => e warn "\nmissing #{e.path} (for rake-compiler)" if e.respond_to? :path - warn "run: rake newb\n\n" + warn "run: bundle install\n\n" end -Hoe.plugin :git -Hoe.plugin :minitest -Hoe.plugin :travis - -HOE = Hoe.spec 'curses' do - self.version = '1.0.2' - - developer 'Eric Hodel', 'drbrain@segment7.net' - developer 'Shugo Maeda', '' +$mswin = /mswin/ =~ RUBY_PLATFORM - license 'Ruby' - license 'BSD-2-Clause' +CLOBBER.include("vendor/#{RUBY_PLATFORM}") if $mswin +CLOBBER.include("vendor/x86-mingw32") +CLOBBER.include("vendor/x64-mingw32") +CLOBBER.include("lib/2.*") +CLOBBER.include("pkg") - self.extra_rdoc_files << 'ext/curses/curses.c' - self.spec_extras[:extensions] = 'ext/curses/extconf.rb' +namespace :build do + desc "Build PDCurses" + task :pdcurses do + mkdir_p "vendor/#{RUBY_PLATFORM}/PDCurses" if $mswin + mkdir_p "vendor/x86-mingw32/PDCurses" + mkdir_p "vendor/x64-mingw32/PDCurses" + chdir "vendor/PDCurses/win32" do + if $mswin + sh "nmake -f vcwin32.mak clean all WIDE=Y DLL=Y" + cp %w[pdcurses.dll pdcurses.lib], "../../#{RUBY_PLATFORM}/PDCurses" + else + sh "make -f mingwin32.mak clean all WIDE=Y DLL=Y" + cp "pdcurses.dll", "../../x86-mingw32/PDCurses" - self.readme_file = 'README.md' - self.history_file = 'History.md' + sh "make -f mingwin32.mak clean all _w64=1 WIDE=Y DLL=Y" + cp "pdcurses.dll", "../../x64-mingw32/PDCurses" + end + end + end +end - self.extra_dev_deps << ['rake-compiler', '~> 0.8'] +namespace :clean do + desc "Clean PDCurses" + task :pdcurses do + chdir "vendor/PDCurses/win32" do + sh "nmake -f vcwin32.mak clean" if $mswin + sh "make -f mingwin32.mak clean _linux_w64=1" + end + end end -if Rake.const_defined? :ExtensionTask then - Rake::ExtensionTask.new 'curses', HOE.spec +spec = eval(File.read(File.expand_path("curses.gemspec", __dir__))) +Rake::ExtensionTask.new(spec.name, spec) do |ext| + if $mswin + ext.config_options << '--with-curses-include=' + + File.expand_path("vendor/PDCurses", __dir__) + + ' --with-curses-version=function --enable-pdcurses-wide' + + ' --enable-pdcurses-dll' + + ' --with-curses-lib=' + + File.expand_path("vendor/#{RUBY_PLATFORM}/PDCurses", __dir__) + spec.files += ["vendor/#{RUBY_PLATFORM}/PDCurses/pdcurses.dll"] + end - task default: :compile - task test: :compile + ext.cross_compile = true + ext.cross_platform = ["x86-mingw32", "x64-mingw32"] + ext.cross_config_options << '--with-curses-include=' + + File.expand_path("vendor/PDCurses", __dir__) + + ' --with-curses-version=function --enable-pdcurses-wide' + ext.cross_config_options << { + 'x86-mingw32' => '--with-curses-lib=' + + File.expand_path("vendor/x86-mingw32/PDCurses", __dir__), + 'x64-mingw32' => '--with-curses-lib=' + + File.expand_path("vendor/x64-mingw32/PDCurses", __dir__) + } + ext.cross_compiling do |_spec| + bin_file = "vendor/#{_spec.platform}/PDCurses/pdcurses.dll" + _spec.files += [bin_file] + stage_file = "#{ext.tmp_dir}/#{_spec.platform}/stage/#{bin_file}" + stage_dir = File.dirname(stage_file) + directory stage_dir + file stage_file => [stage_dir, bin_file] do + cp bin_file, stage_file + end + end end - -# vim: syntax=ruby diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..b2355d2 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,16 @@ +--- +clone_depth: 10 +install: + - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% + - appveyor DownloadFile http://dl.bintray.com/oneclick/OpenKnapsack/x64/pdcurses-3.4-x64-windows.tar.lzma + - 7z e pdcurses-3.4-x64-windows.tar.lzma + - 7z x -y -oC:\Ruby%ruby_version% pdcurses-3.4-x64-windows.tar + - bundle install +build_script: + - rake -rdevkit compile -- --with-curses-dir=C:\Ruby%ruby_version% +test: off +deploy: off +environment: + matrix: + - ruby_version: "22-x64" + - ruby_version: "23-x64" diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig Binary files differdeleted file mode 100644 index fdc971c..0000000 --- a/checksums.yaml.gz.sig +++ /dev/null diff --git a/curses.gemspec b/curses.gemspec index e933b6c..d774965 100644 --- a/curses.gemspec +++ b/curses.gemspec @@ -1,13 +1,17 @@ -require 'rubygems' Gem::Specification.new { |s| s.name = "curses" - s.version = "1.0.2" - s.author = "Shugo Maeda" - s.email = "shugo@ruby-lang.org" - s.homepage = "http://github.com/shugo/curses" + s.version = "1.2.4" + s.author = ["Shugo Maeda", 'Eric Hodel'] + s.email = ["shugo@ruby-lang.org", 'drbrain@segment7.net'] + s.homepage = "https://github.com/ruby/curses" s.platform = Gem::Platform::RUBY - s.summary = "curses binding for Ruby" - s.files = Dir.glob('{lib,ext,sample}/**/*') + ['README.md', 'COPYING', 'BSDL'] + s.summary = "A Ruby binding for curses, ncurses, and PDCurses. curses is an extension library for text UI applications. Formerly part of the Ruby standard library, [curses was removed and placed in this gem][1] with the release of Ruby 2.1.0. (see [ruby/ruby@9c5b2fd][2])" + s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(vendor)/}) } s.extensions = ["ext/curses/extconf.rb"] s.require_path = "lib" + s.required_ruby_version = Gem::Requirement.new('>= 2.1.0') + s.licenses = ['Ruby', 'BSD-2-Clause'] + s.add_development_dependency 'bundler' + s.add_development_dependency 'rake' + s.add_development_dependency 'rake-compiler' } diff --git a/data.tar.gz.sig b/data.tar.gz.sig Binary files differdeleted file mode 100644 index a95ec0d..0000000 --- a/data.tar.gz.sig +++ /dev/null diff --git a/ext/curses/curses.c b/ext/curses/curses.c index 218e545..5d1e315 100644 --- a/ext/curses/curses.c +++ b/ext/curses/curses.c @@ -73,6 +73,9 @@ static VALUE cMouseEvent; static VALUE rb_stdscr; +static rb_encoding *keyboard_encoding; +static rb_encoding *terminal_encoding; + struct windata { WINDOW *window; }; @@ -135,8 +138,21 @@ prep_window(VALUE class, WINDOW *window) return obj; } +#if (defined(HAVE_ADDNWSTR) || defined(HAVE_WADDNWSTR)) && defined(_WIN32) +static inline rb_encoding * +get_wide_encoding(void) +{ + static rb_encoding *utf16le = NULL; + if (!utf16le) { + utf16le = rb_enc_find("utf-16le"); + } + return utf16le; +} +#endif + /*-------------------------- module Curses --------------------------*/ +static void curses_finalize(VALUE); /* * Document-method: Curses.init_screen * @@ -152,6 +168,7 @@ curses_init_screen(void) if (stdscr == 0) { rb_raise(rb_eRuntimeError, "can't initialize curses"); } + rb_set_end_proc(curses_finalize, 0); clear(); rb_stdscr = prep_window(cWindow, stdscr); return rb_stdscr; @@ -250,6 +267,23 @@ curses_clear(VALUE obj) return Qnil; } +#ifdef HAVE_WERASE +/* + * Document-method: Curses.erase + * + * Erase the screen. + */ +static VALUE +curses_erase(VALUE obj) +{ + curses_stdscr(); + werase(stdscr); + return Qnil; +} +#else +#define curses_erase rb_f_notimplement +#endif + /* * Document-method: Curses.clrtoeol * @@ -628,11 +662,19 @@ static VALUE curses_addstr(VALUE obj, VALUE str) { StringValue(str); - str = rb_str_export_locale(str); +#if defined(HAVE_ADDNWSTR) && defined(_WIN32) + str = rb_str_export_to_enc(str, get_wide_encoding()); + curses_stdscr(); + if (!NIL_P(str)) { + addnwstr((wchar_t *)RSTRING_PTR(str), RSTRING_LEN(str) / sizeof(wchar_t)); + } +#else + str = rb_str_export_to_enc(str, terminal_encoding); curses_stdscr(); if (!NIL_P(str)) { addstr(StringValueCStr(str)); } +#endif return Qnil; } @@ -663,7 +705,7 @@ curses_getch(VALUE obj) if (rb_isprint(c)) { char ch = (char)c; - return rb_locale_str_new(&ch, 1); + return rb_external_str_new_with_enc(&ch, 1, keyboard_encoding); } return UINT2NUM(c); } @@ -696,7 +738,7 @@ curses_getstr(VALUE obj) curses_stdscr(); rb_thread_call_without_gvl(getstr_func, rtn, RUBY_UBF_IO, 0); - return rb_locale_str_new_cstr(rtn); + return rb_external_str_new_with_enc(rtn, strlen(rtn), keyboard_encoding); } /* @@ -869,7 +911,8 @@ curses_setscrreg(VALUE obj, VALUE top, VALUE bottom) * Document-method: Curses.attroff * call-seq: attroff(attrs) * - * Turns on the named attributes +attrs+ without affecting any others. + * Turns off the named attributes +attrs+ + * without affecting any others. * * See also Curses::Window.attrset for additional information. */ @@ -885,7 +928,7 @@ curses_attroff(VALUE obj, VALUE attrs) * Document-method: Curses.attron * call-seq: attron(attrs) * - * Turns off the named attributes +attrs+ + * Turns on the named attributes +attrs+ * without turning any other attributes on or off. * * See also Curses::Window.attrset for additional information. @@ -933,7 +976,7 @@ curses_bkgdset(VALUE obj, VALUE ch) { #ifdef HAVE_BKGDSET curses_stdscr(); - bkgdset(NUM2CH(ch)); + bkgdset(NUM2CHTYPE(ch)); #endif return Qnil; } @@ -954,7 +997,7 @@ curses_bkgd(VALUE obj, VALUE ch) { #ifdef HAVE_BKGD curses_stdscr(); - return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse; + return (bkgd(NUM2CHTYPE(ch)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif @@ -977,6 +1020,23 @@ curses_use_default_colors(VALUE obj) #define curses_use_default_colors rb_f_notimplement #endif +#if defined(HAVE_ASSUME_DEFAULT_COLORS) +/* + * tells which colors to paint for color pair 0. + * + * see also the system manual for default_colors(3) + */ +static VALUE +curses_assume_default_colors(VALUE obj, VALUE fg, VALUE bg) +{ + curses_stdscr(); + assume_default_colors(NUM2INT(fg), NUM2INT(bg)); + return Qnil; +} +#else +#define curses_assume_default_colors rb_f_notimplement +#endif + #if defined(HAVE_TABSIZE) /* * Document-method: Curses.TABSIZE= @@ -1562,6 +1622,26 @@ window_clear(VALUE obj) return Qnil; } +#ifdef HAVE_WERASE +/* + * Document-method: Curses::Window.erase + * + * Erase the window. + */ +static VALUE +window_erase(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); + werase(winp->window); + + return Qnil; +} +#else +#define curses_erase rb_f_notimplement +#endif + /* * Document-method: Curses::Window.clrtoeol * @@ -1618,6 +1698,145 @@ window_noutrefresh(VALUE obj) return Qnil; } +#ifdef HAVE_REDRAWWIN +/* + * Document-method: Curses::Window.redraw + * + * Redraws the entire window. + */ +static VALUE +window_redraw(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); + redrawwin(winp->window); + + return Qnil; +} +#else +#define window_redraw rb_f_notimplement +#endif + +#ifdef HAVE_TOUCHWIN +/* + * Document-method: Curses::Window.touch + * + * Treat the window as if it has been modified since the last call of refresh. + */ +static VALUE +window_touch(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); + touchwin(winp->window); + + return Qnil; +} +#else +#define window_touch rb_f_notimplement +#endif + +#ifdef HAVE_UNTOUCHWIN +/* + * Document-method: Curses::Window.untouch + * + * Treat the window as if it has not been modified since the last call of + * refresh. + */ +static VALUE +window_untouch(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); + untouchwin(winp->window); + + return Qnil; +} +#else +#define window_touch rb_f_notimplement +#endif + +#ifdef HAVE_IS_WINTOUCHED +/* + * Document-method: Curses::Window.touched? + * + * Return true if the window has been modified since the last call of refresh. + */ +static VALUE +window_touched(VALUE obj) +{ + struct windata *winp; + + GetWINDOW(obj, winp); + return is_wintouched(winp->window) ? Qtrue : Qfalse; +} +#else +#define window_touched rb_f_notimplement +#endif + +#ifdef HAVE_WTOUCHLN +/* + * Document-method: Curses::Window.touch_line + * call-seq: touch_line(y, n, changed = true) + * + * Make n lines from line y look as if they have (changed = true) or have not + * (changed = false) been modified since the last call of refresh. + */ +static VALUE +window_touch_line(int argc, VALUE *argv, VALUE obj) +{ + struct windata *winp; + VALUE y, n, changed; + int result; + + rb_scan_args(argc, argv, "12", &y, &n, &changed); + if (argc < 2) { + n = INT2NUM(1); + } + if (argc < 3) { + changed = Qtrue; + } + GetWINDOW(obj, winp); + result = wtouchln(winp->window, NUM2INT(y), NUM2INT(n), RTEST(changed)); + if (result == ERR) { + rb_raise(rb_eRangeError, "Out of window"); + } + + return Qnil; +} +#else +#define window_touch_line rb_f_notimplement +#endif + +#ifdef HAVE_IS_LINETOUCHED +/* + * Document-method: Curses::Window.line_touched? + * call-seq: line_touched?(line) + * + * Return true if the specified line has been modified since the last call of + * refresh. + */ +static VALUE +window_line_touched(VALUE obj, VALUE line) +{ + struct windata *winp; + int result, n; + + GetWINDOW(obj, winp); + n = NUM2INT(line); + result = is_linetouched(winp->window, n); + if (result == ERR) { + rb_raise(rb_eArgError, "Invalid line %d", n); + } + return result ? Qtrue : Qfalse; +} +#else +#define window_line_touched rb_f_notimplement +#endif + /* * Document-method: Curses::Window.move * call-seq: move(y,x) @@ -1701,7 +1920,7 @@ window_maxy(VALUE obj) return INT2FIX(getmaxy(winp->window)); #elif defined(getmaxyx) { - int x, y; + int RB_UNUSED_VAR(x), y; getmaxyx(winp->window, y, x); return INT2FIX(y); } @@ -1725,7 +1944,7 @@ window_maxx(VALUE obj) return INT2FIX(getmaxx(winp->window)); #elif defined(getmaxyx) { - int x, y; + int x, RB_UNUSED_VAR(y); getmaxyx(winp->window, y, x); return INT2FIX(x); } @@ -1921,9 +2140,15 @@ window_addstr(VALUE obj, VALUE str) struct windata *winp; StringValue(str); - str = rb_str_export_locale(str); +#if defined(HAVE_WADDNWSTR) && defined(_WIN32) + str = rb_str_export_to_enc(str, get_wide_encoding()); + GetWINDOW(obj, winp); + waddnwstr(winp->window, (wchar_t *)RSTRING_PTR(str), RSTRING_LEN(str) / sizeof(wchar_t)); +#else + str = rb_str_export_to_enc(str, terminal_encoding); GetWINDOW(obj, winp); waddstr(winp->window, StringValueCStr(str)); +#endif } return Qnil; } @@ -1981,7 +2206,7 @@ window_getch(VALUE obj) if (rb_isprint(c)) { char ch = (char)c; - return rb_locale_str_new(&ch, 1); + return rb_external_str_new_with_enc(&ch, 1, keyboard_encoding); } return UINT2NUM(c); } @@ -2018,7 +2243,8 @@ window_getstr(VALUE obj) GetWINDOW(obj, winp); arg.win = winp->window; rb_thread_call_without_gvl(wgetstr_func, (void *)&arg, RUBY_UBF_IO, 0); - return rb_locale_str_new_cstr(arg.rtn); + return rb_external_str_new_with_enc(arg.rtn, strlen(arg.rtn), + keyboard_encoding); } /* @@ -2219,7 +2445,8 @@ window_scrl(VALUE obj, VALUE n) * Document-method: Curses::Window.attroff * call-seq: attroff(attrs) * - * Turns on the named attributes +attrs+ without affecting any others. + * Turns off the named attributes +attrs+ + * without affecting any others. * * See also Curses::Window.attrset */ @@ -2240,7 +2467,7 @@ window_attroff(VALUE obj, VALUE attrs) * Document-method: Curses::Window.attron * call-seq: attron(attrs) * - * Turns off the named attributes +attrs+ + * Turns on the named attributes +attrs+ * without turning any other attributes on or off. * * See also Curses::Window.attrset @@ -2322,7 +2549,7 @@ window_bkgdset(VALUE obj, VALUE ch) struct windata *winp; GetWINDOW(obj,winp); - wbkgdset(winp->window, NUM2CH(ch)); + wbkgdset(winp->window, NUM2CHTYPE(ch)); #endif return Qnil; } @@ -2343,7 +2570,7 @@ window_bkgd(VALUE obj, VALUE ch) struct windata *winp; GetWINDOW(obj,winp); - return (wbkgd(winp->window, NUM2CH(ch)) == OK) ? Qtrue : Qfalse; + return (wbkgd(winp->window, NUM2CHTYPE(ch)) == OK) ? Qtrue : Qfalse; #else return Qfalse; #endif @@ -2362,7 +2589,7 @@ window_getbkgd(VALUE obj) struct windata *winp; GetWINDOW(obj,winp); - return (c = getbkgd(winp->window) != ERR) ? CH2FIX(c) : Qnil; + return (c = getbkgd(winp->window) != ERR) ? ULONG2NUM(c) : Qnil; #else return Qnil; #endif @@ -2521,9 +2748,6 @@ pad_initialize(VALUE obj, VALUE h, VALUE w) return obj; } -#if 1 -#define pad_subpad window_subwin -#else /* * Document-method: Curses::Pad.subpad * call-seq: @@ -2537,7 +2761,7 @@ static VALUE pad_subpad(VALUE obj, VALUE height, VALUE width, VALUE begin_x, VALUE begin_y) { struct windata *padp; - WINDOW *subpad; + WINDOW *sub_pad; VALUE pad; int h, w, x, y; @@ -2546,12 +2770,11 @@ pad_subpad(VALUE obj, VALUE height, VALUE width, VALUE begin_x, VALUE begin_y) x = NUM2INT(begin_x); y = NUM2INT(begin_y); GetWINDOW(obj, padp); - subpad = subwin(padp->window, h, w, x, y); - pad = prep_window(rb_obj_class(obj), subpad); + sub_pad = subpad(padp->window, h, w, x, y); + pad = prep_window(rb_obj_class(obj), sub_pad); return pad; } -#endif /* * Document-method: Curses::Pad.refresh @@ -2622,6 +2845,239 @@ pad_noutrefresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow, } #endif /* HAVE_NEWPAD */ +/* + * Document-method: Curses.keyboard_encoding + * call-seq: Curses.keyboard_encoding + * + * Returns the encoding for keyboard input. + */ +static VALUE +curses_get_keyboard_encoding(VALUE obj) +{ + return rb_enc_from_encoding(keyboard_encoding); +} + +/* + * Document-method: Curses.keyboard_encoding= + * call-seq: Curses.keyboard_encoding = encoding + * + * Sets the encoding for keyboard input. + */ +static VALUE +curses_set_keyboard_encoding(VALUE obj, VALUE enc) +{ + keyboard_encoding = rb_to_encoding(enc); + return enc; +} + +/* + * Document-method: Curses.terminal_encoding + * call-seq: Curses.terminal_encoding + * + * Returns the encoding for terminal output. + */ +static VALUE +curses_get_terminal_encoding(VALUE obj) +{ + return rb_enc_from_encoding(terminal_encoding); +} + +/* + * Document-method: Curses.terminal_encoding= + * call-seq: Curses.terminal_encoding = encoding + * + * Sets the encoding for terminal output. + */ +static VALUE +curses_set_terminal_encoding(VALUE obj, VALUE enc) +{ + terminal_encoding = rb_to_encoding(enc); + return enc; +} + +/* + * Document-method: Curses.unget_char + * call-seq: unget_char(ch) + * + * Places +ch+ back onto the input queue to be returned by + * the next call to Curses.get_char etc. + * + * There is just one input queue for all windows. + */ +static VALUE +curses_unget_char(VALUE obj, VALUE ch) +{ + ID id_ord; + unsigned int c; + + curses_stdscr(); + if (FIXNUM_P(ch)) { + ungetch(NUM2UINT(ch)); + } + else { + StringValue(ch); + CONST_ID(id_ord, "ord"); + c = NUM2UINT(rb_funcall(ch, id_ord, 0)); +#ifdef HAVE_UNGET_WCH + unget_wch(c); +#else + if (c > 0xff) { + rb_raise(rb_eRangeError, "Out of range: %u", c); + } + ungetch(c); +#endif + } + return Qnil; +} + +static VALUE +keyboard_uint_chr(unsigned int ch) +{ + return rb_enc_uint_chr(ch, keyboard_encoding); +} + +#ifdef HAVE_GET_WCH +struct get_wch_arg { + int retval; + wint_t ch; +}; + +static void * +get_wch_func(void *_arg) +{ + struct get_wch_arg *arg = (struct get_wch_arg *) _arg; + arg->retval = get_wch(&arg->ch); + return 0; +} +#endif + +/* + * Document-method: Curses.get_char + * + * Read and returns a character or function key from the window. + * A single or multibyte character is represented by a String, and + * a function key is represented by an Integer. + * Returns nil if no input is ready. + * + * See Curses::Key to all the function KEY_* available + * + */ +static VALUE +curses_get_char(VALUE obj) +{ +#ifdef HAVE_GET_WCH + struct get_wch_arg arg; + + curses_stdscr(); + rb_thread_call_without_gvl(get_wch_func, &arg, RUBY_UBF_IO, 0); + switch (arg.retval) { + case OK: + return keyboard_uint_chr(arg.ch); + case KEY_CODE_YES: + return UINT2NUM(arg.ch); + } + return Qnil; +#else + int c; + + curses_stdscr(); + rb_thread_call_without_gvl(getch_func, &c, RUBY_UBF_IO, 0); + if (c > 0xff) { + return INT2NUM(c); + } + else if (c >= 0) { + return keyboard_uint_chr(c); + } + else { + return Qnil; + } +#endif +} + + +#ifdef HAVE_WGET_WCH +struct wget_wch_arg { + WINDOW *win; + int retval; + wint_t ch; +}; + +static void * +wget_wch_func(void *_arg) +{ + struct wget_wch_arg *arg = (struct wget_wch_arg *) _arg; + arg->retval = wget_wch(arg->win, &arg->ch); + return 0; +} +#endif + +/* + * Document-method: Curses::Window.get_char + * + * Read and returns a character or function key from the window. + * A single or multibyte character is represented by a String, and + * a function key is represented by an Integer. + * Returns nil if no input is ready. + * + * See Curses::Key to all the function KEY_* available + * + */ +static VALUE +window_get_char(VALUE obj) +{ +#ifdef HAVE_WGET_WCH + struct windata *winp; + struct wget_wch_arg arg; + + GetWINDOW(obj, winp); + arg.win = winp->window; + rb_thread_call_without_gvl(wget_wch_func, &arg, RUBY_UBF_IO, 0); + switch (arg.retval) { + case OK: + return keyboard_uint_chr(arg.ch); + case KEY_CODE_YES: + return UINT2NUM(arg.ch); + } + return Qnil; +#else + struct windata *winp; + struct wgetch_arg arg; + + GetWINDOW(obj, winp); + arg.win = winp->window; + rb_thread_call_without_gvl(wgetch_func, (void *)&arg, RUBY_UBF_IO, 0); + if (arg.c > 0xff) { + return INT2NUM(arg.c); + } + else if (arg.c >= 0) { + return keyboard_uint_chr(arg.c); + } + else { + return Qnil; + } +#endif +} + +#ifdef HAVE_PDC_GET_KEY_MODIFIERS +static VALUE +curses_get_key_modifiers(VALUE obj) +{ + return ULONG2NUM(PDC_get_key_modifiers()); +} + +static VALUE +curses_return_key_modifiers(VALUE obj, VALUE flag) +{ + return INT2NUM(PDC_return_key_modifiers(RTEST(flag))); +} + +static VALUE +curses_save_key_modifiers(VALUE obj, VALUE flag) +{ + return INT2NUM(PDC_save_key_modifiers(RTEST(flag))); +} +#endif + /*------------------------- Initialization -------------------------*/ /* @@ -2656,6 +3112,13 @@ pad_noutrefresh(VALUE obj, VALUE pminrow, VALUE pmincol, VALUE sminrow, void Init_curses(void) { +#ifdef HAVE_GET_WCH + keyboard_encoding = rb_locale_encoding(); +#else + keyboard_encoding = rb_ascii8bit_encoding(); +#endif + terminal_encoding = rb_locale_encoding(); + mCurses = rb_define_module("Curses"); /* @@ -2700,6 +3163,7 @@ Init_curses(void) rb_define_module_function(mCurses, "TABSIZE=", curses_tabsize_set, 1); rb_define_module_function(mCurses, "use_default_colors", curses_use_default_colors, 0); + rb_define_module_function(mCurses, "assume_default_colors", curses_assume_default_colors, 2); rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0); rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0); rb_define_module_function(mCurses, "closed?", curses_closed, 0); @@ -2707,6 +3171,7 @@ Init_curses(void) rb_define_module_function(mCurses, "refresh", curses_refresh, 0); rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0); rb_define_module_function(mCurses, "clear", curses_clear, 0); + rb_define_module_function(mCurses, "erase", curses_erase, 0); rb_define_module_function(mCurses, "clrtoeol", curses_clrtoeol, 0); rb_define_module_function(mCurses, "echo", curses_echo, 0); rb_define_module_function(mCurses, "noecho", curses_noecho, 0); @@ -2770,6 +3235,17 @@ Init_curses(void) rb_define_module_function(mCurses, "timeout=", curses_timeout, 1); rb_define_module_function(mCurses, "def_prog_mode", curses_def_prog_mode, 0); rb_define_module_function(mCurses, "reset_prog_mode", curses_reset_prog_mode, 0); + rb_define_module_function(mCurses, "keyboard_encoding", curses_get_keyboard_encoding, 0); + rb_define_module_function(mCurses, "keyboard_encoding=", curses_set_keyboard_encoding, 1); + rb_define_module_function(mCurses, "terminal_encoding", curses_get_terminal_encoding, 0); + rb_define_module_function(mCurses, "terminal_encoding=", curses_set_terminal_encoding, 1); + rb_define_module_function(mCurses, "unget_char", curses_unget_char, 1); + rb_define_module_function(mCurses, "get_char", curses_get_char, 0); +#ifdef HAVE_PDC_GET_KEY_MODIFIERS + rb_define_module_function(mCurses, "get_key_modifiers", curses_get_key_modifiers, 0); + rb_define_module_function(mCurses, "return_key_modifiers", curses_return_key_modifiers, 1); + rb_define_module_function(mCurses, "save_key_modifiers", curses_save_key_modifiers, 1); +#endif { VALUE version; @@ -2808,23 +3284,23 @@ Init_curses(void) * * == Usage * - * require 'curses' + * require "curses" * - * Curses.init_screen() + * Curses.init_screen * * my_str = "LOOK! PONIES!" - * bwin = Curses::Window.new( 10, (my_str.length + 10), - * (Curses.lines - 10) / 2, - * (Curses.cols - (my_str.length + 10)) / 2 ) + * + * height, width = 12, my_str.length + 10 + * top, left = (Curses.lines - height) / 2, (Curses.cols - width) / 2 + * bwin = Curses::Window.new(height, width, top, left) * bwin.box("\\", "/") * bwin.refresh - * win = bwin.subwin( 6, my_str.length + 6, - * (Curses.lines - 6) / 2, - * (Curses.cols - (my_str.length + 6)) / 2 ) - * win.setpos(2,3) + * + * win = bwin.subwin(height - 4, width - 4, top + 2, left + 2) + * win.setpos(2, 3) * win.addstr(my_str) * # or even - * win << "\nORLY" + * win << "\nOH REALLY?" * win << "\nYES!! " + my_str * win.refresh * win.getch @@ -2837,9 +3313,16 @@ Init_curses(void) rb_define_method(cWindow, "subwin", window_subwin, 4); rb_define_method(cWindow, "close", window_close, 0); rb_define_method(cWindow, "clear", window_clear, 0); + rb_define_method(cWindow, "erase", window_erase, 0); rb_define_method(cWindow, "clrtoeol", window_clrtoeol, 0); rb_define_method(cWindow, "refresh", window_refresh, 0); rb_define_method(cWindow, "noutrefresh", window_noutrefresh, 0); + rb_define_method(cWindow, "redraw", window_redraw, 0); + rb_define_method(cWindow, "touch", window_touch, 0); + rb_define_method(cWindow, "untouch", window_untouch, 0); + rb_define_method(cWindow, "touched?", window_touched, 0); + rb_define_method(cWindow, "touch_line", window_touch_line, -1); + rb_define_method(cWindow, "line_touched?", window_line_touched, 1); rb_define_method(cWindow, "box", window_box, -1); rb_define_method(cWindow, "move", window_move, 2); rb_define_method(cWindow, "setpos", window_setpos, 2); @@ -2883,6 +3366,8 @@ Init_curses(void) rb_define_method(cWindow, "nodelay=", window_nodelay, 1); rb_define_method(cWindow, "timeout=", window_timeout, 1); + rb_define_method(cWindow, "get_char", window_get_char, 0); + #ifdef HAVE_NEWPAD /* * Document-class: Curses::Pad @@ -2903,7 +3388,7 @@ Init_curses(void) rb_undef_method(cPad, "subwin"); #endif -#define rb_curses_define_const(c) rb_define_const(mCurses,#c,UINT2NUM(c)) +#define rb_curses_define_const(c) rb_define_const(mCurses,#c,CHTYPE2NUM(c)) #ifdef USE_COLOR /* Document-const: A_ATTRIBUTES @@ -4326,7 +4811,48 @@ Init_curses(void) rb_define_const(mCurses, name, INT2FIX(c - 'A' + 1)); } } +#ifdef PDC_KEY_MODIFIER_SHIFT + /* PDCurses-specific keys */ + rb_curses_define_const(ALT_0); + rb_curses_define_const(ALT_1); + rb_curses_define_const(ALT_2); + rb_curses_define_const(ALT_3); + rb_curses_define_const(ALT_4); + rb_curses_define_const(ALT_5); + rb_curses_define_const(ALT_6); + rb_curses_define_const(ALT_7); + rb_curses_define_const(ALT_8); + rb_curses_define_const(ALT_9); + rb_curses_define_const(ALT_A); + rb_curses_define_const(ALT_B); + rb_curses_define_const(ALT_C); + rb_curses_define_const(ALT_D); + rb_curses_define_const(ALT_E); + rb_curses_define_const(ALT_F); + rb_curses_define_const(ALT_G); + rb_curses_define_const(ALT_H); + rb_curses_define_const(ALT_I); + rb_curses_define_const(ALT_J); + rb_curses_define_const(ALT_K); + rb_curses_define_const(ALT_L); + rb_curses_define_const(ALT_M); + rb_curses_define_const(ALT_N); + rb_curses_define_const(ALT_O); + rb_curses_define_const(ALT_P); + rb_curses_define_const(ALT_Q); + rb_curses_define_const(ALT_R); + rb_curses_define_const(ALT_S); + rb_curses_define_const(ALT_T); + rb_curses_define_const(ALT_U); + rb_curses_define_const(ALT_V); + rb_curses_define_const(ALT_W); + rb_curses_define_const(ALT_X); + rb_curses_define_const(ALT_Y); + rb_curses_define_const(ALT_Z); + rb_curses_define_const(PDC_KEY_MODIFIER_SHIFT); + rb_curses_define_const(PDC_KEY_MODIFIER_CONTROL); + rb_curses_define_const(PDC_KEY_MODIFIER_ALT); + rb_curses_define_const(PDC_KEY_MODIFIER_NUMLOCK); +#endif #undef rb_curses_define_const - - rb_set_end_proc(curses_finalize, 0); } diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb index 9c7ca0e..7bebc1f 100644 --- a/ext/curses/extconf.rb +++ b/ext/curses/extconf.rb @@ -30,9 +30,9 @@ have_library("tinfo", "tgetent") or have_library("termcap", "tgetent") header_library = nil [ + ["ncursesw/curses.h", ["ncursesw"]], ["ncurses.h", ["ncursesw", "ncurses"]], ["ncurses/curses.h", ["ncurses"]], - ["ncursesw/curses.h", ["ncursesw"]], ["curses_colr/curses.h", ["cur_colr"]], ["curses.h", ["curses", "pdcurses"]], # ["xcurses.h", ["XCurses"]], # XCurses (PDCurses for X11) @@ -57,17 +57,20 @@ if header_library for f in %w(beep bkgd bkgdset curs_set deleteln doupdate flash getbkgd getnstr init isendwin keyname keypad resizeterm - scrl set setscrreg ungetch + scrl set setscrreg ungetch addnwstr wattroff wattron wattrset wbkgd wbkgdset wdeleteln wgetnstr - wresize wscrl wsetscrreg + wresize wscrl wsetscrreg werase redrawwin waddnwstr + touchwin untouchwin wtouchln is_linetouched is_wintouched def_prog_mode reset_prog_mode timeout wtimeout nodelay - init_color wcolor_set use_default_colors newpad) + init_color wcolor_set use_default_colors assume_default_colors + newpad unget_wch get_wch wget_wch PDC_get_key_modifiers) have_func(f) || (have_macro(f, curses) && $defs.push(format("-DHAVE_%s", f.upcase))) end + convertible_int('chtype', [["#undef MOUSE_MOVED\n"]]+curses) or abort flag = "-D_XOPEN_SOURCE_EXTENDED" - if try_static_assert("sizeof(char*)>sizeof(int)", - %w[stdio.h stdlib.h]+curses, - flag) + if checking_for("_XOPEN_SOURCE_EXTENDED") { + try_compile(cpp_include(%w[stdio.h stdlib.h]+curses), flag, :werror => true) + } $defs << flag end have_var("ESCDELAY", curses) @@ -129,8 +132,17 @@ if header_library else warn "unexpected value for --with-curses-version: #{with_curses_version}" end - + + if enable_config("pdcurses-wide") + $defs << '-DPDC_WIDE' + end + + if enable_config("pdcurses-dll") + $defs << '-DPDC_DLL_BUILD' + end + if RUBY_VERSION >= '2.1' + create_header create_makefile("curses") else # curses is part of ruby-core pre-2.1.0, so this gem is not required. But diff --git a/lib/curses.rb b/lib/curses.rb index f99ede3..9ea86f8 100644 --- a/lib/curses.rb +++ b/lib/curses.rb @@ -1 +1,23 @@ -require "curses.so" +platform = RUBY_PLATFORM.sub(/i[3-7]86/, "x86") +pdcurses_path = File.expand_path("../vendor/#{platform}/PDCurses", __dir__) +pdcurses_bundled = File.directory?(pdcurses_path) +if pdcurses_bundled + path = ENV["PATH"] + dir = File::ALT_SEPARATOR ? + pdcurses_path.tr("/", File::ALT_SEPARATOR) : dir + dirs = path.split(File::PATH_SEPARATOR) + if !dirs.include?(dir) + ENV["PATH"] = [dir, *dirs].join(File::PATH_SEPARATOR) + end +end + +begin + major, minor, _ = RUBY_VERSION.split(/\./) + require "#{major}.#{minor}/curses.so" +rescue LoadError + require "curses.so" +end + +if pdcurses_bundled + Curses.keyboard_encoding = Encoding::UTF_8 +end diff --git a/metadata.gz.sig b/metadata.gz.sig deleted file mode 100644 index 083b0b3..0000000 --- a/metadata.gz.sig +++ /dev/null @@ -1 +0,0 @@ -]1&Ŕ|S[m;}S+Pגy]0X8Dt>p\]O`*xdv.aN!8DH^sűMhTFu}#ղ2reڲWbqƨdwbu#Ʉ*V͂XvMI?$9O&;Oz=*:溹Pl,I
4O.ApP۶)|O^oardEЎAzLW
\ No newline at end of file diff --git a/sample/hello.rb b/sample/hello.rb index 6308a17..6ef31cd 100755 --- a/sample/hello.rb +++ b/sample/hello.rb @@ -1,13 +1,14 @@ #!/usr/bin/env ruby require "curses" -include Curses def show_message(message) - width = message.length + 6 - win = Window.new(5, width, - (lines - 5) / 2, (cols - width) / 2) - win.box('|', '-') + height = 5 + width = message.length + 6 + top = (Curses.lines - height) / 2 + left = (Curses.cols - width) / 2 + win = Curses::Window.new(height, width, top, left) + win.box("|", "-") win.setpos(2, 3) win.addstr(message) win.refresh @@ -15,16 +16,14 @@ def show_message(message) win.close end -init_screen +Curses.init_screen begin - crmode -# show_message("Hit any key") - setpos((lines - 5) / 2, (cols - 10) / 2) - addstr("Hit any key") - refresh - getch + Curses.crmode + Curses.setpos((Curses.lines - 1) / 2, (Curses.cols - 11) / 2) + Curses.addstr("Hit any key") + Curses.refresh + Curses.getch show_message("Hello, World!") - refresh ensure - close_screen + Curses.close_screen end diff --git a/sample/mouse.rb b/sample/mouse.rb index 49d4802..92c2b96 100755 --- a/sample/mouse.rb +++ b/sample/mouse.rb @@ -5,13 +5,13 @@ include Curses def show_message(*msgs) message = msgs.join - width = message.length + 6 - win = Window.new(5, width, - (lines - 5) / 2, (cols - width) / 2) + height, width = 5, message.length + 6 + top, left = (lines - height) / 2, (cols - width) / 2 + win = Window.new(height, width, top, left) win.keypad = true - win.attron(color_pair(COLOR_RED)){ - win.box(?|, ?-, ?+) - } + win.attron(color_pair(COLOR_RED)) do + win.box("|", "-", "+") + end win.setpos(2, 3) win.addstr(message) win.refresh @@ -21,28 +21,28 @@ end init_screen start_color -init_pair(COLOR_BLUE,COLOR_BLUE,COLOR_WHITE) -init_pair(COLOR_RED,COLOR_RED,COLOR_WHITE) +init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_WHITE) +init_pair(COLOR_RED, COLOR_RED, COLOR_WHITE) crmode noecho stdscr.keypad(true) begin mousemask(BUTTON1_CLICKED|BUTTON2_CLICKED|BUTTON3_CLICKED|BUTTON4_CLICKED) - setpos((lines - 5) / 2, (cols - 10) / 2) - attron(color_pair(COLOR_BLUE)|A_BOLD){ + setpos((lines - 1) / 2, (cols - 5) / 2) + attron(color_pair(COLOR_BLUE)|A_BOLD) do addstr("click") - } + end refresh - while( true ) + loop do c = getch case c when KEY_MOUSE m = getmouse - if( m ) - show_message("getch = #{c.inspect}, ", - "mouse event = #{'0x%x' % m.bstate}, ", - "axis = (#{m.x},#{m.y},#{m.z})") + if m + show_message("getch = #{c.inspect}, ", + "mouse event = #{'0x%x' % m.bstate}, ", + "axis = (#{m.x},#{m.y},#{m.z})") end break end diff --git a/sample/rain.rb b/sample/rain.rb index a5f8fc5..6ed5246 100755 --- a/sample/rain.rb +++ b/sample/rain.rb @@ -1,76 +1,72 @@ #!/usr/bin/env ruby -# rain for a curses test require "curses" -include Curses -def onsig(sig) - close_screen - exit sig +def onsig(signal) + Curses.close_screen + exit signal end -def ranf - rand(32767).to_f / 32767 +def place_string(y, x, string) + Curses.setpos(y, x) + Curses.addstr(string) end -# main # -for i in %w[HUP INT QUIT TERM] - if trap(i, "SIG_IGN") != 0 then # 0 for SIG_IGN - trap(i) {|sig| onsig(sig) } +def cycle_index(index) + (index + 1) % 5 +end + +%w[HUP INT QUIT TERM].each do |sig| + unless trap(sig, "IGNORE") == "IGNORE" # previous handler + trap(sig) {|s| onsig(s) } end end -init_screen -nl -noecho +Curses.init_screen +Curses.nl +Curses.noecho +Curses.curs_set 0 srand -xpos = {} -ypos = {} -r = lines - 4 -c = cols - 4 -for i in 0 .. 4 - xpos[i] = (c * ranf).to_i + 2 - ypos[i] = (r * ranf).to_i + 2 +xpos, ypos = {}, {} +x_range = 2..(Curses.cols - 3) +y_range = 2..(Curses.lines - 3) +(0..4).each do |i| + xpos[i], ypos[i] = rand(x_range), rand(y_range) end i = 0 -while TRUE - x = (c * ranf).to_i + 2 - y = (r * ranf).to_i + 2 +loop do + x, y = rand(x_range), rand(y_range) + place_string(y, x, ".") - setpos(y, x); addstr(".") + place_string(ypos[i], xpos[i], "o") - setpos(ypos[i], xpos[i]); addstr("o") + i = cycle_index(i) + place_string(ypos[i], xpos[i], "O") - i = if i == 0 then 4 else i - 1 end - setpos(ypos[i], xpos[i]); addstr("O") + i = cycle_index(i) + place_string(ypos[i] - 1, xpos[i], "-") + place_string(ypos[i], xpos[i] - 1, "|.|") + place_string(ypos[i] + 1, xpos[i], "-") - i = if i == 0 then 4 else i - 1 end - setpos(ypos[i] - 1, xpos[i]); addstr("-") - setpos(ypos[i], xpos[i] - 1); addstr("|.|") - setpos(ypos[i] + 1, xpos[i]); addstr("-") + i = cycle_index(i) + place_string(ypos[i] - 2, xpos[i], "-") + place_string(ypos[i] - 1, xpos[i] - 1, "/ \\") + place_string(ypos[i], xpos[i] - 2, "| O |") + place_string(ypos[i] + 1, xpos[i] - 1, "\\ /") + place_string(ypos[i] + 2, xpos[i], "-") - i = if i == 0 then 4 else i - 1 end - setpos(ypos[i] - 2, xpos[i]); addstr("-") - setpos(ypos[i] - 1, xpos[i] - 1); addstr("/ \\") - setpos(ypos[i], xpos[i] - 2); addstr("| O |") - setpos(ypos[i] + 1, xpos[i] - 1); addstr("\\ /") - setpos(ypos[i] + 2, xpos[i]); addstr("-") + i = cycle_index(i) + place_string(ypos[i] - 2, xpos[i], " ") + place_string(ypos[i] - 1, xpos[i] - 1, " ") + place_string(ypos[i], xpos[i] - 2, " ") + place_string(ypos[i] + 1, xpos[i] - 1, " ") + place_string(ypos[i] + 2, xpos[i], " ") - i = if i == 0 then 4 else i - 1 end - setpos(ypos[i] - 2, xpos[i]); addstr(" ") - setpos(ypos[i] - 1, xpos[i] - 1); addstr(" ") - setpos(ypos[i], xpos[i] - 2); addstr(" ") - setpos(ypos[i] + 1, xpos[i] - 1); addstr(" ") - setpos(ypos[i] + 2, xpos[i]); addstr(" ") + xpos[i], ypos[i] = x, y - - xpos[i] = x - ypos[i] = y - refresh + Curses.refresh sleep(0.5) end - -# end of main diff --git a/sample/view.rb b/sample/view.rb index 300b3b9..66e861a 100755 --- a/sample/view.rb +++ b/sample/view.rb @@ -3,54 +3,41 @@ require "curses" include Curses -# -# main -# - -if ARGV.size != 1 then - printf("usage: view file\n"); +unless ARGV.size == 1 + puts "usage: #{$0} file" exit end + begin - fp = open(ARGV[0], "r") + data_lines = File.readlines(ARGV[0]) rescue - raise "cannot open file: #{ARGV[1]}" + raise "cannot open file: #{ARGV[0]}" end -# signal(SIGINT, finish) - init_screen -#keypad(stdscr, TRUE) +#keypad(stdscr, true) nonl cbreak noecho -#scrollok(stdscr, TRUE) - -# slurp the file -data_lines = [] -fp.each_line { |l| - data_lines.push(l) -} -fp.close - +#scrollok(stdscr, true) lptr = 0 -while TRUE - i = 0 - while i < lines +loop do + lines.times do |i| setpos(i, 0) #clrtoeol - addstr(data_lines[lptr + i] || '') - i += 1 + addstr(data_lines[lptr + i] || "") end refresh - explicit = FALSE + explicit = false n = 0 - while TRUE + c = nil + loop do c = getch if c =~ /[0-9]/ n = 10 * n + c.to_i + explicit = true else break end @@ -61,31 +48,29 @@ while TRUE case c when "n" #when KEY_DOWN i = 0 - while i < n - if lptr + lines < data_lines.size then - lptr += 1 + n.times do + if lptr + lines < data_lines.size + lptr += 1 else - break + break end i += 1 end #wscrl(i) - when "p" #when KEY_UP i = 0 - while i < n - if lptr > 0 then - lptr -= 1 + n.times do + if lptr > 0 + lptr -= 1 else - break + break end i += 1 end #wscrl(-i) - when "q" break end - end + close_screen diff --git a/sample/view2.rb b/sample/view2.rb index c29c0ce..0f3a49d 100755 --- a/sample/view2.rb +++ b/sample/view2.rb @@ -3,10 +3,10 @@ require "curses" -# A curses based file viewer +# A curses based file viewer. class FileViewer - # Create a new fileviewer, and view the file. + # Create a new FileViewer and view the file. def initialize(filename) @data_lines = [] @screen = nil @@ -16,10 +16,8 @@ class FileViewer interact end - # Perform the curses setup + # Perform the curses setup. def init_curses - # signal(SIGINT, finish) - Curses.init_screen Curses.nonl Curses.cbreak @@ -28,37 +26,32 @@ class FileViewer @screen = Curses.stdscr @screen.scrollok(true) - #$screen.keypad(true) + #@screen.keypad(true) end - # Load the file into memory, and put - # the first part on the curses display. + # Load the file into memory and + # put the first part on the curses display. def load_file(filename) - fp = open(filename, "r") do |fp| - # slurp the file - fp.each_line { |l| - @data_lines.push(l.chop) - } - end + @data_lines = File.readlines(filename).map(&:chomp) @top = 0 - @data_lines[0..@screen.maxy-1].each_with_index{|line, idx| + @data_lines[0..@screen.maxy-1].each_with_index do |line, idx| @screen.setpos(idx, 0) @screen.addstr(line) - } - @screen.setpos(0,0) + end + @screen.setpos(0, 0) @screen.refresh rescue raise "cannot open file '#{filename}' for reading" end - # Scroll the display up by one line + # Scroll the display up by one line. def scroll_up - if( @top > 0 ) + if @top > 0 @screen.scrl(-1) @top -= 1 str = @data_lines[@top] - if( str ) + if str @screen.setpos(0, 0) @screen.addstr(str) end @@ -68,13 +61,13 @@ class FileViewer end end - # Scroll the display down by one line + # Scroll the display down by one line. def scroll_down - if( @top + @screen.maxy < @data_lines.length ) + if @top + @screen.maxy < @data_lines.length @screen.scrl(1) @top += 1 str = @data_lines[@top + @screen.maxy - 1] - if( str ) + if str @screen.setpos(@screen.maxy - 1, 0) @screen.addstr(str) end @@ -85,53 +78,49 @@ class FileViewer end # Allow the user to interact with the display. - # This uses EMACS-like keybindings, and also + # This uses Emacs-like keybindings, and also # vi-like keybindings as well, except that left # and right move to the beginning and end of the # file, respectively. def interact - while true + loop do result = true c = Curses.getch case c - when Curses::KEY_DOWN, Curses::KEY_CTRL_N, ?j + when Curses::KEY_DOWN, Curses::KEY_CTRL_N, "j" result = scroll_down - when Curses::KEY_UP, Curses::KEY_CTRL_P, ?k + when Curses::KEY_UP, Curses::KEY_CTRL_P, "k" result = scroll_up - when Curses::KEY_NPAGE, ?\s # white space - for i in 0..(@screen.maxy - 2) - if( ! scroll_down ) - if( i == 0 ) - result = false - end + when Curses::KEY_NPAGE, " " + (@screen.maxy - 1).times do |i| + if !scroll_down && i == 0 + result = false break end end when Curses::KEY_PPAGE - for i in 0..(@screen.maxy - 2) - if( ! scroll_up ) - if( i == 0 ) - result = false - end + (@screen.maxy - 1).times do |i| + if !scroll_up && i == 0 + result = false break end end - when Curses::KEY_LEFT, Curses::KEY_CTRL_T, ?h - while( scroll_up ) + when Curses::KEY_LEFT, Curses::KEY_CTRL_T, "h" + while scroll_up end - when Curses::KEY_RIGHT, Curses::KEY_CTRL_B, ?l - while( scroll_down ) + when Curses::KEY_RIGHT, Curses::KEY_CTRL_B, "l" + while scroll_down end - when ?q + when "q" break else - @screen.setpos(0,0) + @screen.setpos(0, 0) @screen.addstr("[unknown key `#{Curses.keyname(c)}'=#{c}] ") end - if( !result ) + if !result Curses.beep end - @screen.setpos(0,0) + @screen.setpos(0, 0) end Curses.close_screen end @@ -140,8 +129,8 @@ end # If we are being run as a main program... if __FILE__ == $0 - if ARGV.size != 1 then - printf("usage: #{$0} file\n"); + unless ARGV.size == 1 + puts "usage: #{$0} file" exit end |