class Fir::Indent

Constants

BEGIN_IMPLICIT_TOKEN
BEGIN_MIDWAY_TOKEN
IF_MIDWAY_TOKEN
IndentBlock
OPEN_HEREDOC_TOKEN
OPEN_TOKENS
OPTIONAL_DO_TOKENS
Position
Token
WHEN_MIDWAY_TOKEN

Attributes

array_stack[R]
delimiter_stack[R]
heredoc_stack[R]
lines[R]
paren_stack[R]
stack[R]

Public Class Methods

new(lines) click to toggle source
# File lib/fir/indent.rb, line 15
def initialize(lines)
  @lines = lines
  @stack = []
  @delimiter_stack = []
  @array_stack = []
  @paren_stack = []
  @heredoc_stack = []
end

Public Instance Methods

generate() click to toggle source
# File lib/fir/indent.rb, line 32
def generate
  indents = lines.each.with_index.with_object([]) do |(line, line_index), deltas|
    delta = stack.length
    delta += array_stack.length if in_array?
    delta += paren_stack.length if in_paren?
    delta += heredoc_stack.length if in_heredoc?
    line.split(' ').each_with_index do |word, word_index|
      token = construct_token(word, word_index, line_index)
      if any_open?(token)
        stack.push(token)
      elsif any_midway?(token)
        delta -= 1
      elsif any_close?(token)
        delta -= 1
        stack.pop
      elsif string_open_token?(token)
        delimiter_stack.push(token)
      elsif string_close_token?(token)
        delimiter_stack.pop
      elsif open_array_token?(token)
        array_stack.push(token)
      elsif close_array_token?(token)
        delta -= 1 if array_stack.last.position.y != token.position.y
        array_stack.pop
      elsif open_paren_token?(token)
        paren_stack.push(token)
      elsif close_paren_token?(token)
        delta -= 1 if paren_stack.last.position.y != token.position.y
        paren_stack.pop
      elsif open_heredoc_token?(token)
        heredoc_stack.push(token)
      elsif close_heredoc_token?(token)
        delta -= 1 if heredoc_stack.last.position.y != token.position.y
        heredoc_stack.pop
      end
    end
    deltas << delta
  end
  IndentBlock.new(indents, executable?(indents, lines))
end

Private Instance Methods

any_close?(token) click to toggle source
# File lib/fir/indent.rb, line 107
def any_close?(token)
  !in_string? &&
    !in_heredoc? &&
    closing_token?(token) ||
    when_close_token?(token)
end
any_midway?(token) click to toggle source
# File lib/fir/indent.rb, line 99
def any_midway?(token)
  !in_string? &&
    !in_heredoc? &&
    if_midway_token?(token) ||
    begin_midway_token?(token) ||
    when_midway_token?(token)
end
any_open?(token) click to toggle source
# File lib/fir/indent.rb, line 91
def any_open?(token)
  !in_string? &&
    !in_heredoc? &&
    open_token?(token) ||
    when_open_token?(token) ||
    unmatched_do_token?(token)
end
begin_midway_token?(token) click to toggle source
# File lib/fir/indent.rb, line 218
def begin_midway_token?(token)
  return false unless token.position.x.zero? && stack.last
  (BEGIN_MIDWAY_TOKEN.include?(token.word) && stack.last.word == 'begin') ||
    BEGIN_IMPLICIT_TOKEN.include?(token.word)
end
close_array_token?(token) click to toggle source
# File lib/fir/indent.rb, line 144
def close_array_token?(token)
  !in_string? &&
    in_array? &&
    token.word[-1] == ']'
end
close_heredoc_token?(token) click to toggle source
# File lib/fir/indent.rb, line 133
def close_heredoc_token?(token)
  !in_string? &&
    in_heredoc? &&
    heredoc_stack.last.word[3..-1] == token.word
end
close_paren_token?(token) click to toggle source
# File lib/fir/indent.rb, line 155
def close_paren_token?(token)
  !in_string? &&
    in_paren? &&
    token.word[-1] == '}'
end
closing_token?(token) click to toggle source
# File lib/fir/indent.rb, line 185
def closing_token?(token)
  token.word == 'end' && in_block? && token.position.x.zero?
end
construct_token(word, word_index, line_index) click to toggle source
# File lib/fir/indent.rb, line 75
def construct_token(word, word_index, line_index)
  position = Position.new(word_index, line_index)
  Token.new(word, position)
end
executable?(indents, lines) click to toggle source
# File lib/fir/indent.rb, line 80
def executable?(indents, lines)
  indents[-1].zero? &&
    lines[-1] == '' &&
    !in_block? &&
    !in_string? &&
    !in_heredoc? &&
    !in_paren? &&
    !in_array? &&
    !lines.all? { |line| line == '' }
end
if_midway_token?(token) click to toggle source
# File lib/fir/indent.rb, line 212
def if_midway_token?(token)
  return false unless IF_MIDWAY_TOKEN.include?(token.word) && token.position.x.zero?
  return false unless stack.last&.word == 'if'
  true
end
in_array?() click to toggle source
# File lib/fir/indent.rb, line 161
def in_array?
  array_stack.length.positive?
end
in_block?() click to toggle source
# File lib/fir/indent.rb, line 173
def in_block?
  stack.length.positive?
end
in_heredoc?() click to toggle source
# File lib/fir/indent.rb, line 177
def in_heredoc?
  heredoc_stack.length.positive?
end
in_paren?() click to toggle source
# File lib/fir/indent.rb, line 169
def in_paren?
  paren_stack.length.positive?
end
in_string?() click to toggle source
# File lib/fir/indent.rb, line 165
def in_string?
  delimiter_stack.length.positive?
end
open_array_token?(token) click to toggle source
# File lib/fir/indent.rb, line 139
def open_array_token?(token)
  !in_string? &&
    token.word[0] == '['
end
open_heredoc_token?(token) click to toggle source
# File lib/fir/indent.rb, line 125
def open_heredoc_token?(token)
  !in_string? &&
    !in_heredoc? &&
    token.word.length > 3 &&
    OPEN_HEREDOC_TOKEN.include?(token.word[0..2]) &&
    (token.word[3..-1] == token.word[3..-1].upcase)
end
open_paren_token?(token) click to toggle source
# File lib/fir/indent.rb, line 150
def open_paren_token?(token)
  !in_string? &&
    token.word[0] == '{'
end
open_token?(token) click to toggle source
# File lib/fir/indent.rb, line 181
def open_token?(token)
  OPEN_TOKENS.include?(token.word) && token.position.x.zero?
end
string_close_token?(token) click to toggle source
# File lib/fir/indent.rb, line 120
def string_close_token?(token)
  in_string? &&
    ((token.word[-1] == delimiter_stack.last.word[0]) && (token.word[-2] != "\\"))
end
string_open_token?(token) click to toggle source
# File lib/fir/indent.rb, line 114
def string_open_token?(token)
  (token.word[0] == '\'' || token.word[0] == '"') &&
    !((token.word.length > 1) && token.word[-1] == token.word[0]) &&
    !in_string?
end
unmatched_do_token?(token) click to toggle source
# File lib/fir/indent.rb, line 189
def unmatched_do_token?(token)
  return false unless token.word == 'do'
  !(OPTIONAL_DO_TOKENS.include?(stack.last&.word) &&
    (token.position.y == stack.last&.position&.y))
end
when_close_token?(token) click to toggle source
# File lib/fir/indent.rb, line 206
def when_close_token?(token)
  return false unless token.word == 'end' && token.position.x.zero?
  return false unless stack.last&.word == 'when'
  true
end
when_midway_token?(token) click to toggle source
# File lib/fir/indent.rb, line 200
def when_midway_token?(token)
  return false unless WHEN_MIDWAY_TOKEN.include?(token.word) && token.position.x.zero?
  return false unless stack.last&.word == 'when'
  true
end
when_open_token?(token) click to toggle source
# File lib/fir/indent.rb, line 195
def when_open_token?(token)
  return false unless token.word == 'when' && token.position.x.zero?
  stack.last&.word != 'when'
end