module Oppen
class Wadler
attr_reader :config
attr_reader :current_indent
attr_reader :space
attr_reader :new_line
attr_reader :out
attr_reader :tokens
attr_reader :width
def initialize(config: Config.wadler, space: ' ',
new_line: "\n", out: StringIO.new, width: 80)
@config = config
@current_indent = 0
@space = space
@width = width
@new_line = new_line
@out = out
@tokens = []
end
def output
if !tokens.last.is_a? Oppen::Token::EOF
tokens << Oppen.eof
end
Oppen.print(tokens:, new_line:, config:, space:, out:, width:)
end
def group(indent = 0, open_obj = '', close_obj = '',
break_type = Oppen::Token::BreakType::CONSISTENT)
raise ArgumentError, "#{open_obj.nil? ? 'open_obj' : 'close_obj'} cannot be nil" \
if open_obj.nil? || close_obj.nil?
tokens <<
case break_type
in Oppen::Token::BreakType::CONSISTENT
Oppen.begin_consistent(offset: indent)
in Oppen::Token::BreakType::INCONSISTENT
Oppen.begin_inconsistent(offset: indent)
end
if !open_obj.empty?
self.break
text(open_obj)
end
yield
if !close_obj.empty?
self.break
text(close_obj)
end
tokens << Oppen.end
end
def nest(indent, open_obj = '', close_obj = '',
break_type = Oppen::Token::BreakType::CONSISTENT)
raise ArgumentError, "#{open_obj.nil? ? 'open_obj' : 'close_obj'} cannot be nil" \
if open_obj.nil? || close_obj.nil?
@current_indent += indent
if !open_obj.empty?
text(open_obj)
self.break
end
begin
yield
ensure
@current_indent -= indent
end
return if close_obj.empty?
self.break
text(close_obj)
end
def text(value, width: value.length)
tokens << Oppen.string(value, width:)
end
def breakable(str = ' ', width: str.length, line_continuation: '')
tokens << Oppen.break(str, width:, line_continuation:, offset: current_indent)
end
def break(line_continuation: '')
tokens << Oppen.line_break(line_continuation:, offset: current_indent)
end
end
end