pax_global_header 0000666 0000000 0000000 00000000064 13704310745 0014516 g ustar 00root root 0000000 0000000 52 comment=51527002ab58271e80c0716db4a9529a2b14a533 tty-screen-0.8.1/ 0000775 0000000 0000000 00000000000 13704310745 0013621 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/.editorconfig 0000664 0000000 0000000 00000000226 13704310745 0016276 0 ustar 00root root 0000000 0000000 root = true [*.rb] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true tty-screen-0.8.1/.github/ 0000775 0000000 0000000 00000000000 13704310745 0015161 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/.github/FUNDING.yml 0000664 0000000 0000000 00000000024 13704310745 0016772 0 ustar 00root root 0000000 0000000 github: piotrmurach tty-screen-0.8.1/.github/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000001106 13704310745 0017664 0 ustar 00root root 0000000 0000000 ### Are you in the right place? * For issues or feature requests file a GitHub issue in this repository * For general questions or discussion post in [Gitter](https://gitter.im/piotrmurach/tty) ### Describe the problem A brief description of the issue/feature. ### Steps to reproduce the problem ``` Your code here to reproduce the issue ``` ### Actual behaviour What happened? This could be a description, log output, error raised etc... ### Expected behaviour What did you expect to happen? ### Describe your environment * OS version: * Ruby version: * TTY::Screen version: tty-screen-0.8.1/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000000676 13704310745 0020773 0 ustar 00root root 0000000 0000000 ### Describe the change What does this Pull Request do? ### Why are we doing this? Any related context as to why is this is a desirable change. ### Benefits How will the library improve? ### Drawbacks Possible drawbacks applying this change. ### Requirements Put an X between brackets on each line if you have done the item: [] Tests written & passing locally? [] Code style checked? [] Rebased with `master` branch? [] Documentaion updated? tty-screen-0.8.1/.gitignore 0000664 0000000 0000000 00000000166 13704310745 0015614 0 ustar 00root root 0000000 0000000 /.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ *.bundle *.so *.o *.a mkmf.log tty-screen-0.8.1/.rspec 0000664 0000000 0000000 00000000100 13704310745 0014725 0 ustar 00root root 0000000 0000000 --format documentation --color --require spec_helper --warnings tty-screen-0.8.1/.rubocop.yml 0000664 0000000 0000000 00000001266 13704310745 0016100 0 ustar 00root root 0000000 0000000 Lint/AssignmentInCondition: Enabled: false Metrics/AbcSize: Max: 30 Metrics/BlockLength: CountComments: true Max: 25 ExcludedMethods: [] Exclude: - "spec/**/*" Metrics/ClassLength: Max: 1500 Metrics/CyclomaticComplexity: Enabled: false Metrics/LineLength: Max: 80 Metrics/MethodLength: Max: 20 Naming/BinaryOperatorParameterName: Enabled: false Style/AsciiComments: Enabled: false Style/LambdaCall: SupportedStyles: - call - braces Style/StringLiterals: EnforcedStyle: double_quotes Style/TrivialAccessors: Enabled: false # { ... } for multi-line blocks is okay Style/BlockDelimiters: Enabled: false Style/CommentedKeyword: Enabled: false tty-screen-0.8.1/.travis.yml 0000664 0000000 0000000 00000000612 13704310745 0015731 0 ustar 00root root 0000000 0000000 --- language: ruby before_install: "gem install bundler -v '< 2.0'" script: "bundle exec rake ci" rvm: - 2.0 - 2.1 - 2.2 - 2.3 - 2.4 - 2.5 - 2.6 - 2.7 - ruby-head - jruby-9.2.11.1 - jruby-head - truffleruby matrix: allow_failures: - rvm: ruby-head - rvm: jruby-head - rvm: jruby-9.2.11.1 - rvm: truffleruby fast_finish: true branches: only: master tty-screen-0.8.1/CHANGELOG.md 0000664 0000000 0000000 00000012002 13704310745 0015425 0 ustar 00root root 0000000 0000000 # Change log ## [v0.8.1] - 2020-07-17 ### Fixed * Fix name resolution with TTY::File by Alexey Nikitin (@tank-bohr) ## [v0.8.0] - 2020-05-28 ### Added * Add #windows? platform check * Add #command_exist? to see if an executable exists before running it * Add performance tests ### Changed * Change #jruby? method to hoist within module * Change #size_from_win_api to check only on windows platform and hoist definition within module * Change #size_from_java to hoist within module * Change #size_from_ioctl to: * check solaris-like system * scan all streams to see if any attached to a terminal * hoist definition within module * Change #size_from_io_console to perform check on JRuby as well * Change #size_from_readline to attempt to load readline gem * Change #run_command to execute command directly without sub shell or temp files ## [v0.7.1] - 2020-02-02 ### Changed * Change gemspec to add metadata, remove test artifacts and load version directly ## [v0.7.0] - 2019-05-19 ### Changed * Change gemspec to load files directly without using git * Change to relax development dependencies ## [v0.6.5] - 2018-07-13 ### Changed * Change to namespace version file to allow for direct vendoring ## [v0.6.4] - 2017-12-22 ### Fixed * Fix to suppress stderr output from run_command by Tero Marttila(@SpComb) ## [v0.6.3] - 2017-11-22 ### Changed * Change #size_from_tput & #size_from_stty to capture generic IO and command execution errors to make the calls more robust ### Fixed * Fix #size_from_ioctl to handle Errno errors and deal with Errno::EOPNOTSUPP ## [v0.6.2] - 2017-11-04 ### Fixed * Fix #size_from_java to provide size only for non-zero values * Fix #size_from_ioctl to provide size only for non-zero values ## [v0.6.1] - 2017-10-29 ### Fixed * Fix #size_from_win_api to provide size if non zero to avoid [1,1] size ## [v0.6.0] - 2017-10-29 ### Added * Add #size_from_ioctl check for reading terminal size with Unix ioctl * Add #size_from_java check for reading terminal size from Java on JRuby * Add #size_from_win_api check for reading terminal size from Windows C API ### Changed * Change TTY::Screen to a module without any state * Change to prefix all checks with `size` keyword * Change gemspec to require ruby >= 2.0.0 * Remove #try_io_console and inline with io-console check * Remove #default_size and replace with constant * Remove TTY::Screen::Size class ## [v0.5.1] - 2017-10-26 ### Changed * Change #from_io_console to return nil when no size present * Change #run_command to silently ignore any errors ### Fixed * Fix #from_readline check to prevent from failing on missing api call * Fix #from_stty to only extract size when stty command returns output * Fix #run_command to correctly capture command output and fix #from_tput check ## [v0.5.0] - 2016-01-03 ### Changed * Change size to accept environment as input * Remove Color detection, available as tty-color gem dependency ## [v0.4.3] - 2015-11-01 ### Added * Add NoValue to Color class to mark failure of reading color value ### Changed * Change Color class supports? to recognize lack of color value ### Fixed * Fix issue with #from_curses method and remove ensure block ## [v0.4.2] - 2015-10-31 ### Changed * Change visibility of output to prevent warnings ## [v0.4.1] - 2015-10-31 ### Changed * Change to switch off verbose mode by default ## [v0.4.0] - 2015-09-12 ### Added * Add terminal color support detection ## [v0.3.0] - 2015-09-11 ### Fixed * Fix bug loading standard library ## [v0.2.0] - 2015-05-11 ### Changed * Change to stop memoization of screen class instance method ### Fixed * Fix bug with screen detection from_io_console by @luxflux [v0.8.1]: https://github.com/piotrmurach/tty-screen/compare/v0.8.0...v0.8.1 [v0.8.0]: https://github.com/piotrmurach/tty-screen/compare/v0.7.1...v0.8.0 [v0.7.1]: https://github.com/piotrmurach/tty-screen/compare/v0.7.0...v0.7.1 [v0.7.0]: https://github.com/piotrmurach/tty-screen/compare/v0.6.5...v0.7.0 [v0.6.5]: https://github.com/piotrmurach/tty-screen/compare/v0.6.4...v0.6.5 [v0.6.4]: https://github.com/piotrmurach/tty-screen/compare/v0.6.3...v0.6.4 [v0.6.3]: https://github.com/piotrmurach/tty-screen/compare/v0.6.2...v0.6.3 [v0.6.2]: https://github.com/piotrmurach/tty-screen/compare/v0.6.1...v0.6.2 [v0.6.1]: https://github.com/piotrmurach/tty-screen/compare/v0.6.0...v0.6.1 [v0.6.0]: https://github.com/piotrmurach/tty-screen/compare/v0.5.1...v0.6.0 [v0.5.1]: https://github.com/piotrmurach/tty-screen/compare/v0.5.0...v0.5.1 [v0.5.0]: https://github.com/piotrmurach/tty-screen/compare/v0.4.3...v0.5.0 [v0.4.3]: https://github.com/piotrmurach/tty-screen/compare/v0.4.2...v0.4.3 [v0.4.2]: https://github.com/piotrmurach/tty-screen/compare/v0.4.1...v0.4.2 [v0.4.1]: https://github.com/piotrmurach/tty-screen/compare/v0.4.0...v1.4.1 [v0.4.0]: https://github.com/piotrmurach/tty-screen/compare/v0.3.0...v0.4.0 [v0.3.0]: https://github.com/piotrmurach/tty-screen/compare/v0.2.0...v0.3.0 [v0.2.0]: https://github.com/piotrmurach/tty-screen/compare/v0.1.0...v0.2.0 [v0.1.0]: https://github.com/piotrmurach/tty-screen/compare/v0.1.0 tty-screen-0.8.1/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000006235 13704310745 0016426 0 ustar 00root root 0000000 0000000 # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at piotr@piotrmurach.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ tty-screen-0.8.1/Gemfile 0000664 0000000 0000000 00000000505 13704310745 0015114 0 ustar 00root root 0000000 0000000 source "https://rubygems.org" gemspec gem "coveralls", "~> 0.8.22" gem "simplecov", "~> 0.16.1" gem "yardstick", "~> 0.9.9" if RUBY_VERSION.split(".")[1].to_i > 0 && !(/jruby/ =~ RUBY_ENGINE) gem "rspec-benchmark", "~> 0.6.0" end if RUBY_VERSION.split(".")[1].to_i > 3 && !(/jruby/ =~ RUBY_ENGINE) gem "io-console" end tty-screen-0.8.1/LICENSE.txt 0000664 0000000 0000000 00000002055 13704310745 0015446 0 ustar 00root root 0000000 0000000 Copyright (c) 2014 Piotr Murach MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. tty-screen-0.8.1/README.md 0000664 0000000 0000000 00000005231 13704310745 0015101 0 ustar 00root root 0000000 0000000
# TTY::Screen [][gitter] [][gem] [][travis] [][appveyor] [][codeclimate] [][coverage] [][inchpages] [gitter]: https://gitter.im/piotrmurach/tty [gem]: http://badge.fury.io/rb/tty-screen [travis]: http://travis-ci.org/piotrmurach/tty-screen [appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-screen [codeclimate]: https://codeclimate.com/github/piotrmurach/tty-screen [coverage]: https://coveralls.io/r/piotrmurach/tty-screen [inchpages]: http://inch-ci.org/github/piotrmurach/tty-screen > Terminal screen size detection which works on Linux, OS X and Windows/Cygwin platforms and supports MRI, JRuby, TruffleRuby and Rubinius interpreters. **TTY::Screen** provides independent terminal screen size detection component for [TTY](https://github.com/piotrmurach/tty) toolkit. ## Installation Add this line to your application's Gemfile: ```ruby gem 'tty-screen' ``` And then execute: $ bundle Or install it yourself as: $ gem install tty-screen ## 1. Usage **TTY::Screen** allows you to detect terminal screen size by calling `size` method which returns [height, width] tuple. ```ruby TTY::Screen.size # => [51, 280] ``` To read terminal width do: ```ruby TTY::Screen.width # => 280 TTY::Screen.columns # => 280 TTY::Screen.cols # => 280 ``` Similarly, to read terminal height do: ```ruby TTY::Screen.height # => 51 TTY::Screen.rows # => 51 TTY::Screen.lines # => 51 ``` ## Contributing 1. Fork it ( https://github.com/piotrmurach/tty-screen/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. ## Copyright Copyright (c) 2014 Piotr Murach. See LICENSE for further details. tty-screen-0.8.1/Rakefile 0000664 0000000 0000000 00000000217 13704310745 0015266 0 ustar 00root root 0000000 0000000 require "bundler/gem_tasks" FileList["tasks/**/*.rake"].each(&method(:import)) desc "Run all specs" task ci: %w[ spec ] task default: :spec tty-screen-0.8.1/appveyor.yml 0000664 0000000 0000000 00000001066 13704310745 0016214 0 ustar 00root root 0000000 0000000 --- install: - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% - ruby --version - gem --version - bundle install build: off test_script: - bundle exec rake ci environment: matrix: - ruby_version: "200" - ruby_version: "200-x64" - ruby_version: "21" - ruby_version: "21-x64" - ruby_version: "22" - ruby_version: "22-x64" - ruby_version: "23" - ruby_version: "23-x64" - ruby_version: "24" - ruby_version: "24-x64" - ruby_version: "25" - ruby_version: "25-x64" - ruby_version: "26" - ruby_version: "26-x64" tty-screen-0.8.1/bin/ 0000775 0000000 0000000 00000000000 13704310745 0014371 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/bin/console 0000775 0000000 0000000 00000000531 13704310745 0015760 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby require "bundler/setup" require "tty/screen" # You can add fixtures and/or initialization code here to make experimenting # with your gem easier. You can also use a different console, if you like. # (If you use this, don't forget to add pry to your Gemfile!) # require "pry" # Pry.start require "irb" IRB.start(__FILE__) tty-screen-0.8.1/bin/setup 0000775 0000000 0000000 00000000203 13704310745 0015452 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash set -euo pipefail IFS=$'\n\t' set -vx bundle install # Do any other automated setup that you need to do here tty-screen-0.8.1/lib/ 0000775 0000000 0000000 00000000000 13704310745 0014367 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/lib/tty-screen.rb 0000664 0000000 0000000 00000000036 13704310745 0017010 0 ustar 00root root 0000000 0000000 require_relative 'tty/screen' tty-screen-0.8.1/lib/tty/ 0000775 0000000 0000000 00000000000 13704310745 0015207 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/lib/tty/screen.rb 0000664 0000000 0000000 00000021502 13704310745 0017013 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true begin require "rbconfig" rescue LoadError end require_relative "screen/version" module TTY # Used for detecting screen properties # # @api public module Screen # Helper to define private functions def self.private_module_function(name) module_function(name) private_class_method(name) end case (defined?(::RbConfig) ? ::RbConfig::CONFIG["host_os"] : ::RUBY_PLATFORM) when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ def windows?; true end else def windows?; false end end module_function :windows? case (defined?(::RbConfig) ? ::RbConfig::CONFIG["ruby_install_name"] : ::RUBY_ENGINE) when /jruby/ def jruby?; true end else def jruby?; false end end module_function :jruby? # Default terminal size # # @api public DEFAULT_SIZE = [27, 80].freeze @env = ENV @output = $stderr class << self # Holds the environment variables # @api public attr_accessor :env # Specifies an output stream # @api public attr_accessor :output end # Get terminal rows and columns # # @return [Array[Integer, Integer]] # return rows and columns # # @api public def size(verbose: false) size_from_java(verbose: verbose) || size_from_win_api(verbose: verbose) || size_from_ioctl || size_from_io_console(verbose: verbose) || size_from_readline(verbose: verbose) || size_from_tput || size_from_stty || size_from_env || size_from_ansicon || size_from_default end module_function :size def width size[1] end module_function :width alias columns width alias cols width module_function :columns module_function :cols def height size[0] end module_function :height alias rows height alias lines height module_function :rows module_function :lines # Default size for the terminal # # @return [Array[Integer, Integer]] # # @api private def size_from_default DEFAULT_SIZE end module_function :size_from_default # Determine terminal size with a Windows native API # # @return [nil, Array[Integer, Integer]] # # @api private if windows? STDOUT_HANDLE = 0xFFFFFFF5 def size_from_win_api(verbose: false) require "fiddle" unless defined?(Fiddle) kernel32 = Fiddle::Handle.new("kernel32") get_std_handle = Fiddle::Function.new(kernel32["GetStdHandle"], [-Fiddle::TYPE_INT], Fiddle::TYPE_INT) get_console_buffer_info = Fiddle::Function.new( kernel32["GetConsoleScreenBufferInfo"], [Fiddle::TYPE_LONG, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) format = "SSSSSssssSS" buffer = ([0] * format.size).pack(format) stdout_handle = get_std_handle.(STDOUT_HANDLE) get_console_buffer_info.(stdout_handle, buffer) _, _, _, _, _, left, top, right, bottom, = buffer.unpack(format) size = [bottom - top + 1, right - left + 1] return size if nonzero_column?(size[1] - 1) rescue LoadError warn "no native fiddle module found" if verbose rescue Fiddle::DLError # non windows platform or no kernel32 lib end else def size_from_win_api(verbose: false); nil end end module_function :size_from_win_api # Determine terminal size on jruby using native Java libs # # @return [nil, Array[Integer, Integer]] # # @api private if jruby? def size_from_java(verbose: false) require "java" java_import "jline.TerminalFactory" terminal = TerminalFactory.get size = [terminal.get_height, terminal.get_width] return size if nonzero_column?(size[1]) rescue warn "failed to import java terminal package" if verbose end else def size_from_java(verbose: false); nil end end module_function :size_from_java # Detect screen size by loading io/console lib # # On Windows io_console falls back to reading environment # variables. This means any user changes to the terminal # size won't be reflected in the runtime of the Ruby app. # # @return [nil, Array[Integer, Integer]] # # @api private def size_from_io_console(verbose: false) require "io/console" unless IO.method_defined?(:winsize) return unless @output.tty? && @output.respond_to?(:winsize) size = @output.winsize size if nonzero_column?(size[1]) rescue Errno::EOPNOTSUPP # no support for winsize on output rescue LoadError warn "no native io/console support or io-console gem" if verbose end module_function :size_from_io_console if !jruby? && @output.respond_to?(:ioctl) TIOCGWINSZ = 0x5413 # linux TIOCGWINSZ_PPC = 0x40087468 # macos, freedbsd, netbsd, openbsd TIOCGWINSZ_SOL = 0x5468 # solaris # Read terminal size from Unix ioctl # # @return [nil, Array[Integer, Integer]] # # @api private def size_from_ioctl format = "SSSS" buffer = ([0] * format.size).pack(format) if ioctl?(TIOCGWINSZ, buffer) || ioctl?(TIOCGWINSZ_PPC, buffer) || ioctl?(TIOCGWINSZ_SOL, buffer) rows, cols, = buffer.unpack(format)[0..1] return [rows, cols] if nonzero_column?(cols) end end # Check if ioctl can be called and any of the streams is # attached to a terminal. # # @return [Boolean] # True if any of the streams is attached to a terminal, false otherwise. # # @api private def ioctl?(control, buf) ($stdout.ioctl(control, buf) >= 0) || ($stdin.ioctl(control, buf) >= 0) || ($stderr.ioctl(control, buf) >= 0) rescue SystemCallError false end module_function :ioctl? else def size_from_ioctl; nil end end module_function :size_from_ioctl # Detect screen size using Readline # # @api private def size_from_readline(verbose: false) require "readline" unless defined?(::Readline) return unless ::Readline.respond_to?(:get_screen_size) size = ::Readline.get_screen_size size if nonzero_column?(size[1]) rescue LoadError warn "no readline gem" if verbose rescue NotImplementedError end module_function :size_from_readline # Detect terminal size from tput utility # # @api private def size_from_tput return unless @output.tty? && command_exist?("tput") lines = run_command("tput", "lines") return unless lines cols = run_command("tput", "cols") [lines.to_i, cols.to_i] if nonzero_column?(lines) end module_function :size_from_tput # Detect terminal size from stty utility # # @api private def size_from_stty return unless @output.tty? && command_exist?("stty") out = run_command("stty", "size") return unless out size = out.split.map(&:to_i) size if nonzero_column?(size[1]) end module_function :size_from_stty # Detect terminal size from environment # # After executing Ruby code if the user changes terminal # dimensions during code runtime, the code won't be notified, # and hence won't see the new dimensions reflected in its copy # of LINES and COLUMNS environment variables. # # @return [nil, Array[Integer, Integer]] # # @api private def size_from_env return unless @env["COLUMNS"] =~ /^\d+$/ size = [(@env["LINES"] || @env["ROWS"]).to_i, @env["COLUMNS"].to_i] size if nonzero_column?(size[1]) end module_function :size_from_env # Detect terminal size from Windows ANSICON # # @api private def size_from_ansicon return unless @env["ANSICON"] =~ /\((.*)x(.*)\)/ size = [$2, $1].map(&:to_i) size if nonzero_column?(size[1]) end module_function :size_from_ansicon # Check if command exists # # @return [Boolean] # # @api private def command_exist?(command) exts = env.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR) env.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir| file = ::File.join(dir, command) ::File.exist?(file) || exts.any? { |ext| ::File.exist?("#{file}#{ext}") } end end private_module_function :command_exist? # Runs command silently capturing the output # # @api private def run_command(*args) %x(#{args.join(" ")}) rescue IOError, SystemCallError nil end private_module_function :run_command # Check if number is non zero # # return [Boolean] # # @api private def nonzero_column?(column) column.to_i > 0 end private_module_function :nonzero_column? end # Screen end # TTY tty-screen-0.8.1/lib/tty/screen/ 0000775 0000000 0000000 00000000000 13704310745 0016466 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/lib/tty/screen/version.rb 0000664 0000000 0000000 00000000152 13704310745 0020476 0 ustar 00root root 0000000 0000000 # fronzen_string_literal: true module TTY module Screen VERSION = "0.8.1" end # Screen end # TTY tty-screen-0.8.1/spec/ 0000775 0000000 0000000 00000000000 13704310745 0014553 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/spec/perf/ 0000775 0000000 0000000 00000000000 13704310745 0015507 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/spec/perf/size_spec.rb 0000664 0000000 0000000 00000001050 13704310745 0020014 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true require "io/console" require "rspec-benchmark" RSpec.describe TTY::Screen, ".size" do include RSpec::Benchmark::Matchers it "detectes size 13x slower than io-console" do expect { TTY::Screen.size }.to perform_slower_than { IO.console.winsize }.at_most(13).times end it "performs at least 28K i/s" do expect { TTY::Screen.size }.to perform_at_least(28_000).ips end it "allocates at most 10 objects" do expect { TTY::Screen.size }.to perform_allocation(10).objects end end tty-screen-0.8.1/spec/spec_helper.rb 0000664 0000000 0000000 00000002014 13704310745 0017366 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true if ENV['COVERAGE'] || ENV['TRAVIS'] require 'simplecov' require 'coveralls' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter ]) SimpleCov.start do command_name 'spec' add_filter 'spec' end end require 'tty-screen' RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end # Limits the available syntax to the non-monkey patched syntax that is recommended. config.disable_monkey_patching! # This setting enables warnings. It's recommended, but in some cases may # be too noisy due to issues in dependencies. config.warnings = true if config.files_to_run.one? config.default_formatter = 'doc' end config.profile_examples = 2 config.order = :random Kernel.srand config.seed end tty-screen-0.8.1/spec/unit/ 0000775 0000000 0000000 00000000000 13704310745 0015532 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/spec/unit/screen_spec.rb 0000664 0000000 0000000 00000020413 13704310745 0020350 0 ustar 00root root 0000000 0000000 require "delegate" RSpec.describe TTY::Screen do class Output < SimpleDelegator def winsize [100, 200] end def ioctl(control, buf) buf.replace("3\x00\xD3\x00\xF2\x04\xCA\x02\x00") 0 end end let(:output) { Output.new(StringIO.new("", "w+")) } subject(:screen) { described_class } describe "#size" do it "correctly falls through choices" do old_output = screen.output screen.output = StringIO.new { size_from_java: nil, size_from_win_api: nil, size_from_ioctl: nil, size_from_io_console: [51, 280], size_from_readline: nil }.each do |size_method, result| allow(screen).to receive(size_method) { result } end expect(screen.size).to eq([51, 280]) expect(screen).to have_received(:size_from_java) expect(screen).to have_received(:size_from_win_api) expect(screen).to have_received(:size_from_ioctl) expect(screen).to_not have_received(:size_from_readline) screen.output = old_output end end describe "#size_from_win_api" do it "doesn't check size on non-windows platform", unless: TTY::Screen.windows? do expect(screen.size_from_win_api).to eq(nil) end end describe "#size_from_java" do it "doesn't import java on non-jruby platform", unless: TTY::Screen.jruby? do expect(screen.size_from_java).to eq(nil) end it "imports java library on jruby", if: TTY::Screen.jruby? do class << screen def java_import(*args); end end terminal = double(:terminal, get_height: 51, get_width: 211) factory = double(:factory, get: terminal) stub_const("TTY::Screen::TerminalFactory", factory) allow(screen).to receive(:jruby?).and_return(true) allow(screen).to receive(:require).with("java").and_return(true) allow(screen).to receive(:java_import) expect(screen.size_from_java).to eq([51, 211]) end end describe "#size_from_io_console" do it "calcualtes the size" do old_output = screen.output screen.output = StringIO.new allow(IO).to receive(:method_defined?).with(:winsize) { true } allow(screen.output).to receive(:tty?) { true } allow(screen.output).to receive(:respond_to?) { true } allow(screen.output).to receive(:winsize) { [100, 200] } expect(screen.size_from_io_console).to eq([100, 200]) expect(screen.output).to have_received(:winsize) screen.output = old_output end it "doesn't calculate size if io/console not available" do allow(IO).to receive(:method_defined?).with(:winsize).and_return(false) allow(screen).to receive(:require).with("io/console").and_raise(LoadError) expect(screen.size_from_io_console).to eq(nil) end it "doesn't calculate size if it is run without a console" do allow(IO).to receive(:method_defined?).with(:winsize) { true } allow(screen).to receive(:require).with("io/console") { true } allow(screen.output).to receive(:tty?) { true } allow(screen.output).to receive(:respond_to?).with(:winsize) { false } expect(screen.size_from_io_console).to eq(nil) end end describe "#size_from_ioctl" do def replace_streams(*streams) originals = [$stdout, $stdin, $stderr] $stdout, $stdin, $stderr = output, output, output yield ensure $stdout, $stdin, $stderr = *originals end it "reads terminal size", unless: TTY::Screen.windows? || TTY::Screen.jruby? do replace_streams do expect(screen.size_from_ioctl).to eq([51, 211]) end end it "skips reading on jruby", if: TTY::Screen.jruby? do expect(screen.size_from_ioctl).to eq(nil) end end describe "#size_from_tput" do it "doesn't run command if outside of terminal" do allow(screen.output).to receive(:tty?).and_return(false) expect(screen.size_from_tput).to eq(nil) end it "doesn't run command if not available" do allow(screen).to receive(:command_exist?).and_return(false) expect(screen.size_from_tput).to eq(nil) end it "runs tput commands" do allow(screen.output).to receive(:tty?).and_return(true) allow(screen).to receive(:command_exist?).with("tput").and_return(true) allow(screen).to receive(:run_command).with("tput", "lines").and_return(51) allow(screen).to receive(:run_command).with("tput", "cols").and_return(280) expect(screen.size_from_tput).to eq([51, 280]) end it "doesn't return zero size" do allow(screen.output).to receive(:tty?).and_return(true) allow(screen).to receive(:command_exist?).with("tput").and_return(true) allow(screen).to receive(:run_command).with("tput", "lines").and_return(0) allow(screen).to receive(:run_command).with("tput", "cols").and_return(0) expect(screen.size_from_tput).to eq(nil) end end describe "#size_from_stty" do it "doesn't run command if outside of terminal" do allow(screen.output).to receive(:tty?).and_return(false) expect(screen.size_from_stty).to eq(nil) end it "doesn't run command if not available" do allow(screen).to receive(:command_exist?).and_return(false) expect(screen.size_from_stty).to eq(nil) end it "runs stty commands" do allow(screen.output).to receive(:tty?).and_return(true) allow(screen).to receive(:command_exist?).with("stty").and_return(true) allow(screen).to receive(:run_command).with("stty", "size").and_return("51 280") expect(screen.size_from_stty).to eq([51, 280]) end it "doesn't return zero size" do allow(screen.output).to receive(:tty?).and_return(true) allow(screen).to receive(:command_exist?).with("stty").and_return(true) allow(screen).to receive(:run_command).with("stty", "size").and_return("0 0") expect(screen.size_from_stty).to eq(nil) end end describe "#size_from_env" do it "doesn't calculate size without COLUMNS key" do old_env = screen.env screen.env = {"COLUMNS" => nil} expect(screen.size_from_env).to eq(nil) screen.env = old_env end it "extracts lines and columns from environment" do old_env = screen.env screen.env = {"COLUMNS" => "280", "LINES" => "51"} expect(screen.size_from_env).to eq([51, 280]) screen.env = old_env end it "doesn't return zero size" do old_env = screen.env screen.env = {"COLUMNS" => "0", "LINES" => "0"} expect(screen.size_from_env).to eq(nil) screen.env = old_env end end describe "#size_from_ansicon" do it "doesn't calculate size without ANSICON key" do old_env = screen.env screen.env = {"ANSICON" => nil} expect(screen.size_from_ansicon).to eq(nil) screen.env = old_env end it "extracts lines and columns from environment" do old_env = screen.env screen.env = {"ANSICON" => "(280x51)"} expect(screen.size_from_ansicon).to eq([51, 280]) screen.env = old_env end it "doesn't return zero size" do old_env = screen.env screen.env = {"ANSICON" => "(0x0)"} expect(screen.size_from_ansicon).to eq(nil) screen.env = old_env end end describe "#size_from_default" do it "suggests default terminal size" do [:size_from_java, :size_from_win_api, :size_from_ioctl, :size_from_io_console, :size_from_readline, :size_from_tput, :size_from_stty, :size_from_env, :size_from_ansicon].each do |method| allow(screen).to receive(method).and_return(nil) end expect(screen.size).to eq([27, 80]) end end describe "#width" do it "calcualtes screen width" do allow(screen).to receive(:size).and_return([51, 280]) expect(screen.width).to eq(280) end it "aliases width to columns and cols" do allow(screen).to receive(:size).and_return([51, 280]) expect(screen.columns).to eq(280) expect(screen.cols).to eq(280) end end describe "#height" do it "calcualtes screen height" do allow(screen).to receive(:size).and_return([51, 280]) expect(screen.height).to eq(51) end it "aliases width to rows and lines" do allow(screen).to receive(:size).and_return([51, 280]) expect(screen.rows).to eq(51) expect(screen.lines).to eq(51) end end end tty-screen-0.8.1/tasks/ 0000775 0000000 0000000 00000000000 13704310745 0014746 5 ustar 00root root 0000000 0000000 tty-screen-0.8.1/tasks/console.rake 0000664 0000000 0000000 00000000326 13704310745 0017255 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true desc "Load gem inside irb console" task :console do require "irb" require "irb/completion" require_relative "../lib/tty-screen" ARGV.clear IRB.start end task :c => :console tty-screen-0.8.1/tasks/coverage.rake 0000664 0000000 0000000 00000000336 13704310745 0017407 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true desc "Measure code coverage" task :coverage do begin original, ENV["COVERAGE"] = ENV["COVERAGE"], "true" Rake::Task["spec"].invoke ensure ENV["COVERAGE"] = original end end tty-screen-0.8.1/tasks/spec.rake 0000664 0000000 0000000 00000001517 13704310745 0016550 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true begin require "rspec/core/rake_task" desc "Run all specs" RSpec::Core::RakeTask.new(:spec) do |task| task.pattern = "spec/{unit,integration}{,/*/**}/*_spec.rb" end namespace :spec do desc "Run unit specs" RSpec::Core::RakeTask.new(:unit) do |task| task.pattern = "spec/unit{,/*/**}/*_spec.rb" end desc "Run integration specs" RSpec::Core::RakeTask.new(:integration) do |task| task.pattern = "spec/integration{,/*/**}/*_spec.rb" end desc "Run performance specs" RSpec::Core::RakeTask.new(:perf) do |task| task.pattern = "spec/perf{,/*/**}/*_spec.rb" end end rescue LoadError %w[spec spec:unit spec:integration spec:perf].each do |name| task name do $stderr.puts "In order to run #{name}, do `gem install rspec`" end end end tty-screen-0.8.1/tty-screen.gemspec 0000664 0000000 0000000 00000002737 13704310745 0017274 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true require_relative "lib/tty/screen/version" Gem::Specification.new do |spec| spec.name = "tty-screen" spec.version = TTY::Screen::VERSION spec.authors = ["Piotr Murach"] spec.email = ["piotr@piotrmurach.com"] spec.summary = %q{Terminal screen size detection which works on Linux, OS X and Windows/Cygwin platforms and supports MRI, JRuby, TruffleRuby and Rubinius interpreters.} spec.description = %q{Terminal screen size detection which works on Linux, OS X and Windows/Cygwin platforms and supports MRI, JRuby, TruffleRuby and Rubinius interpreters.} spec.homepage = "https://ttytoolkit.org" spec.license = "MIT" if spec.respond_to?(:metadata=) spec.metadata = { "allowed_push_host" => "https://rubygems.org", "bug_tracker_uri" => "https://github.com/piotrmurach/tty-screen/issues", "changelog_uri" => "https://github.com/piotrmurach/tty-screen/blob/master/CHANGELOG.md", "documentation_uri" => "https://www.rubydoc.info/gems/tty-screen", "homepage_uri" => spec.homepage, "source_code_uri" => "https://github.com/piotrmurach/tty-screen" } end spec.files = Dir["lib/**/*"] spec.extra_rdoc_files = ["README.md", "CHANGELOG.md", "LICENSE.txt"] spec.require_paths = ["lib"] spec.required_ruby_version = Gem::Requirement.new(">= 2.0.0") spec.add_development_dependency "rake" spec.add_development_dependency "rspec", ">= 3.0" end