Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release HighLine 3.0.0 (Ruby 3.3.0) #265

Merged
merged 14 commits into from
Jan 5, 2024
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
os: [ubuntu-latest]
ruby-version:
- head
- '3.3'
- '3.2'
- '3.1'
- '3.0'
Expand All @@ -22,7 +23,7 @@ jobs:
- os: windows-latest
ruby-version: head
- os: windows-latest
ruby-version: '3.1'
ruby-version: '3.3'
- os: windows-latest
ruby-version: mingw
- os: windows-latest
Expand All @@ -32,7 +33,7 @@ jobs:
- os: macos-latest
ruby-version: 'head'
- os: macos-latest
ruby-version: '3.1'
ruby-version: '3.3'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 3 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

Below is a complete listing of changes for each revision of HighLine.

### 3.0.0.pre.1 / 2023-04-27
### 3.0.0 / 2024-01-05
* PR #265 - Change Readline for Reline for Ruby 3.3 compat (@abinoam)
* PR #264 - Add abbrev gem as dependency (@mathieujobin)
* PR #263 - Release 3.0.0.pre.1
* Raise minimum Ruby version requirement to 3.0
* PR #262 - Do not call stty on non-tty (@kbrock)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ For more examples see the examples/ directory of this project.
Requirements
------------

HighLine from version >= 1.7.0 requires ruby >= 1.9.3
HighLine from version >= 3.0.0 requires ruby >= 3.0.0

Installing
----------
Expand Down
1 change: 1 addition & 0 deletions highline.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ DESCRIPTION
spec.add_development_dependency "rake"
spec.add_development_dependency "minitest"
spec.add_development_dependency "dry-types"
spec.add_development_dependency "reline"
end
18 changes: 14 additions & 4 deletions lib/highline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,8 @@ def list(items, mode = :rows, option = nil)
#
# @param statement [Statement, String] what to be said
def say(statement)
statement = render_statement(statement)
return if statement.empty?

statement = (indentation + statement)
statement = render_and_ident_statement(statement)
return statement if statement.empty?

# Don't add a newline if statement ends with whitespace, OR
# if statement ends with whitespace before a color escape code.
Expand All @@ -386,6 +384,18 @@ def say(statement)
end
end

# Renders and indents a statement.
#
# Note: extracted here to be used by readline to render its prompt.
#
# @param statement [String] The statement to be rendered and indented.
# @return [String] The rendered and indented statement.
def render_and_ident_statement(statement)
statement = render_statement(statement)
statement = (indentation + statement) unless statement.empty?
statement
end

# Renders a statement using {HighLine::Statement}
# @param statement [String] any string
# @return [Statement] rendered statement
Expand Down
8 changes: 2 additions & 6 deletions lib/highline/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def initialize(template, answer_type)
#
attr_accessor :echo
#
# Use the Readline library to fetch input. This allows input editing as
# Use the Reline library to fetch input. This allows input editing as
# well as keeping a history. In addition, tab will auto-complete
# within an Array of choices or a file listing.
#
Expand All @@ -125,6 +125,7 @@ def initialize(template, answer_type)
# specified _input_ stream.
#
attr_accessor :readline

#
# Used to control whitespace processing for the answer to this question.
# See HighLine::Question.remove_whitespace() for acceptable settings.
Expand Down Expand Up @@ -580,11 +581,6 @@ def ask_on_error_msg
end
end

# readline() needs to handle its own output, but readline only supports
# full line reading. Therefore if question.echo is anything but true,
# the prompt will not be issued. And we have to account for that now.
# Also, JRuby-1.7's ConsoleReader.readLine() needs to be passed the prompt
# to handle line editing properly.
# @param highline [HighLine] context
# @return [void]
def show_question(highline)
Expand Down
3 changes: 2 additions & 1 deletion lib/highline/question_asker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def initialize(question, highline)
#
# @return [String] answer
def ask_once
question.show_question(@highline)
# If in readline mode, let reline take care of the prompt
question.show_question(@highline) unless question.readline

begin
question.get_response_or_default(@highline)
Expand Down
10 changes: 6 additions & 4 deletions lib/highline/terminal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ def get_line(question, highline)
# Get one line using #readline_read
# @param (see #get_line)
def get_line_with_readline(question, highline)
require "readline" # load only if needed
require "reline" # load only if needed

raw_answer = readline_read(question)
raw_answer = readline_read(question, highline)

if !raw_answer && highline.track_eof?
raise EOFError, "The input stream is exhausted."
Expand All @@ -109,20 +109,22 @@ def get_line_with_readline(question, highline)
# Use readline to read one line
# @param question [HighLine::Question] question from where to get
# autocomplete candidate strings
def readline_read(question)
def readline_read(question, highline)
# prep auto-completion
unless question.selection.empty?
Readline.completion_proc = lambda do |str|
question.selection.grep(/\A#{Regexp.escape(str)}/)
end
end

# TODO: Check if this is still needed after Reline
# work-around ugly readline() warnings
old_verbose = $VERBOSE
$VERBOSE = nil

raw_answer = run_preserving_stty do
Readline.readline("", true)
prompt = highline.render_and_ident_statement(question)
Readline.readline(prompt, true)
end

$VERBOSE = old_verbose
Expand Down
2 changes: 1 addition & 1 deletion lib/highline/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

class HighLine
# The version of the installed library.
VERSION = "3.0.0.pre.1".freeze
VERSION = "3.0.0".freeze
end
5 changes: 5 additions & 0 deletions test/acceptance/acceptance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
rescue NameError
'not availabe'
end}
Reline::VERSION: #{begin
Reline::VERSION
rescue NameError
'not available'
end}
ENV['SHELL']: #{ENV['SHELL']}
ENV['TERM']: #{ENV['TERM']}
ENV['TERM_PROGRAM']: #{ENV['TERM_PROGRAM']}
Expand Down
89 changes: 0 additions & 89 deletions test/test_highline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

require "highline"
require "stringio"
require "readline"
require "tempfile"

# if HighLine::CHARACTER_MODE == "Win32API"
Expand Down Expand Up @@ -387,94 +386,6 @@ def test_after_some_chars_erase_line_does_not_enter_prompt_when_utf8
assert_equal(4, @output.string.count("\b"))
end

def test_readline_mode
#
# Rubinius (and JRuby) seems to be ignoring
# Readline input and output assignments. This
# ruins testing.
#
# But it doesn't mean readline is not working
# properly on rubinius or jruby.
#

terminal = @terminal.terminal

if terminal.jruby? || terminal.rubinius? || terminal.windows?
skip "We can't test Readline on JRuby, Rubinius and Windows yet"
end

# Creating Tempfiles here because Readline.input
# and Readline.output only accepts a File object
# as argument (not any duck type as StringIO)

temp_stdin = Tempfile.new "temp_stdin"
temp_stdout = Tempfile.new "temp_stdout"

Readline.input = @input = File.open(temp_stdin.path, "w+")
Readline.output = @output = File.open(temp_stdout.path, "w+")

@terminal = HighLine.new(@input, @output)

@input << "any input\n"
@input.rewind

answer = @terminal.ask("Prompt: ") do |q|
q.readline = true
end

@output.rewind
output = @output.read

assert_equal "any input", answer
assert_match "Prompt: any input\n", output

@input.close
@output.close
Readline.input = STDIN
Readline.output = STDOUT
end

def test_readline_mode_with_limit_set
temp_stdin = Tempfile.new "temp_stdin"
temp_stdout = Tempfile.new "temp_stdout"

Readline.input = @input = File.open(temp_stdin.path, "w+")
Readline.output = @output = File.open(temp_stdout.path, "w+")

@terminal = HighLine.new(@input, @output)

@input << "any input\n"
@input.rewind

answer = @terminal.ask("Prompt: ") do |q|
q.limit = 50
q.readline = true
end

@output.rewind
output = @output.read

assert_equal "any input", answer
assert_equal "Prompt: any input\n", output

@input.close
@output.close
Readline.input = STDIN
Readline.output = STDOUT
end

def test_readline_on_non_echo_question_has_prompt
@input << "you can't see me"
@input.rewind
answer = @terminal.ask("Please enter some hidden text: ") do |q|
q.readline = true
q.echo = "*"
end
assert_equal("you can't see me", answer)
assert_equal("Please enter some hidden text: ****************\n",
@output.string)
end

def test_character_reading
# WARNING: This method does NOT cover Unix and Windows savvy testing!
@input << "12345"
Expand Down
95 changes: 95 additions & 0 deletions test/test_reline.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require "test_helper"
require "reline"

class TestReline < Minitest::Test
def setup
HighLine.reset
@input = StringIO.new
@output = StringIO.new
@terminal = HighLine.new(@input, @output)
end

def test_readline_mode
# See #267
skip "We need vterm / yamatanooroti based tests for reline"

# Creating Tempfiles here because Readline.input
# and Readline.output only accepts a File object
# as argument (not any duck type as StringIO)

temp_stdin = Tempfile.new "temp_stdin"
temp_stdout = Tempfile.new "temp_stdout"

Reline.input = @input = File.open(temp_stdin.path, "w+")
Reline.output = @output = File.open(temp_stdout.path, "w+")

@terminal = HighLine.new(@input, @output)

@input << "any input\n"
@input.rewind

answer = @terminal.ask("Prompt: ") do |q|
q.readline = true
end

@output.rewind
output = @output.read

assert_equal "any input", answer
assert_match "Prompt: any input\n", output

@input.close
@output.close
Reline.input = STDIN
Reline.output = STDOUT
end

def test_readline_mode_with_limit_set
temp_stdin = Tempfile.new "temp_stdin"
temp_stdout = Tempfile.new "temp_stdout"

Reline.input = @input = File.open(temp_stdin.path, "w+")
Reline.output = @output = File.open(temp_stdout.path, "w+")

@terminal = HighLine.new(@input, @output)

@input << "any input\n"
@input.rewind

answer = @terminal.ask("Prompt: ") do |q|
q.limit = 50
q.readline = true
end

@output.rewind
output = @output.read

assert_equal "any input", answer

# after migrating to Reline, we can't make assertions about the output
# without using vterm / yamatanooroti. See #267
#
# assert_equal "Prompt: any input\n", output

@input.close
@output.close
Reline.input = STDIN
Reline.output = STDOUT
end

def test_readline_on_non_echo_question_has_prompt
@input << "you can't see me"
@input.rewind
answer = @terminal.ask("Please enter some hidden text: ") do |q|
q.readline = true
q.echo = "*"
end
assert_equal("you can't see me", answer)

# after migrating to Reline, we can't make assertions about the output
# without using vterm / yamatanooroti. See #267
#
# assert_equal("Please enter some hidden text: ****************\n",
# @output.string)
end
end
Loading