diff options
Diffstat (limited to 'lib/syntax_suggest/core_ext.rb')
-rw-r--r-- | lib/syntax_suggest/core_ext.rb | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb new file mode 100644 index 0000000000..40f5fe1375 --- /dev/null +++ b/lib/syntax_suggest/core_ext.rb @@ -0,0 +1,101 @@ +# 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 + class MiniStringIO + def initialize(isatty: $stderr.isatty) + @string = +"" + @isatty = isatty + end + + attr_reader :isatty + def puts(value = $/, **) + @string << value + end + + attr_reader :string + end + end + + SyntaxError.prepend 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 + file = if highlight + SyntaxSuggest::PathnameFromMessage.new(super(highlight: false, **kwargs)).call.name + else + SyntaxSuggest::PathnameFromMessage.new(message).call.name + end + + io = SyntaxSuggest::MiniStringIO.new + + if file + SyntaxSuggest.call( + io: io, + source: file.read, + filename: file, + terminal: highlight + ) + annotation = io.string + + 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 + } +else + autoload :Pathname, "pathname" + + # Monkey patch kernel to ensure that all `require` calls call the same + # method + module Kernel + 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 |