ruby/lib/syntax_suggest/core_ext.rb
Schneems 226cfda306 [ruby/syntax_suggest] Fix missing line break due to puts logic
In #225 it was reported that the output looks incorrect:

```
$ cat /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
def x.y.z
end
$ ruby /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
/tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb: --> /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
expected a delimiter to close the parametersunexpected '.', ignoring it
> 1  def x.y.z
> 2  end
```

Specifically:

```
expected a delimiter to close the parametersunexpected '.', ignoring it
```

However this does not show up when executing the debug executable:

```
$ bin/bundle exec exe/syntax_suggest /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb
--> /tmp/4a71c7e417cc9eac0971e3a2519b295c/scratch.rb

expected a delimiter to close the parameters
unexpected '.', ignoring it

> 1  def x.y.z
> 2  end
```

This is because `exe/syntax_suggest` uses STDOUT.puts while calling `ruby` with the filename uses a fake IO object represented by MiniStringIO. This class was incorrectly not adding a newline to the end of the print.

The fix was to move the class to it's own file where it can be tested and then fix the behavior.

close https://github.com/ruby/syntax_suggest/pull/225

https://github.com/ruby/syntax_suggest/commit/d2ecd94a3b

Co-authored-by: Andy Yong <andyywz@gmail.com>
2024-11-15 01:31:26 +00:00

97 lines
2.6 KiB
Ruby

# frozen_string_literal: true
# Ruby 3.2+ has a cleaner way to hook into Ruby that doesn't use `require`
if SyntaxError.method_defined?(:detailed_message)
module SyntaxSuggest
# SyntaxSuggest.module_for_detailed_message [Private]
#
# Used to monkeypatch SyntaxError via Module.prepend
def self.module_for_detailed_message
Module.new {
def detailed_message(highlight: true, syntax_suggest: true, **kwargs)
return super unless syntax_suggest
require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
message = super
if path
file = Pathname.new(path)
io = SyntaxSuggest::MiniStringIO.new
SyntaxSuggest.call(
io: io,
source: file.read,
filename: file,
terminal: highlight
)
annotation = io.string
annotation += "\n" unless annotation.end_with?("\n")
annotation + message
else
message
end
rescue => e
if ENV["SYNTAX_SUGGEST_DEBUG"]
$stderr.warn(e.message)
$stderr.warn(e.backtrace)
end
# Ignore internal errors
message
end
}
end
end
SyntaxError.prepend(SyntaxSuggest.module_for_detailed_message)
else
autoload :Pathname, "pathname"
#--
# Monkey patch kernel to ensure that all `require` calls call the same
# method
#++
module Kernel
# :stopdoc:
module_function
alias_method :syntax_suggest_original_require, :require
alias_method :syntax_suggest_original_require_relative, :require_relative
alias_method :syntax_suggest_original_load, :load
def load(file, wrap = false)
syntax_suggest_original_load(file)
rescue SyntaxError => e
require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
SyntaxSuggest.handle_error(e)
end
def require(file)
syntax_suggest_original_require(file)
rescue SyntaxError => e
require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
SyntaxSuggest.handle_error(e)
end
def require_relative(file)
if Pathname.new(file).absolute?
syntax_suggest_original_require file
else
relative_from = caller_locations(1..1).first
relative_from_path = relative_from.absolute_path || relative_from.path
syntax_suggest_original_require File.expand_path("../#{file}", relative_from_path)
end
rescue SyntaxError => e
require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE)
SyntaxSuggest.handle_error(e)
end
end
end