class Textbringer::RubyMode
Constants
- BLOCK_END
- INDENT_BEG_RE
Public Class Methods
new(buffer)
click to toggle source
Calls superclass method
Textbringer::ProgrammingMode::new
# File lib/textbringer/modes/ruby_mode.rb, line 92 def initialize(buffer) super(buffer) @buffer[:indent_level] = CONFIG[:ruby_indent_level] @buffer[:indent_tabs_mode] = CONFIG[:ruby_indent_tabs_mode] end
Public Instance Methods
backward_definition(n = number_prefix_arg || 1)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 119 def backward_definition(n = number_prefix_arg || 1) tokens = Ripper.lex(@buffer.to_s).reverse @buffer.beginning_of_line n.times do |i| tokens = tokens.drop_while { |(l, _), e, t| l >= @buffer.current_line || e != :on_kw || /\A(?:class|module|def)\z/ !~ t } (line,), = tokens.first if line.nil? @buffer.beginning_of_buffer break end @buffer.goto_line(line) tokens = tokens.drop(1) end while /\s/ =~ @buffer.char_after @buffer.forward_char end end
comment_start()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 88 def comment_start "#" end
compile(cmd = read_from_minibuffer("Compile: ", default: default_compile_command))
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 140 def compile(cmd = read_from_minibuffer("Compile: ", default: default_compile_command)) shell_execute(cmd, buffer_name: "*Ruby compile result*", mode: BacktraceMode) end
default_compile_command()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 150 def default_compile_command @buffer[:ruby_compile_command] || if File.exist?("Rakefile") prefix = File.exist?("Gemfile") ? "bundle exec " : "" prefix + "rake" elsif @buffer.file_name ruby_install_name + " " + @buffer.file_name else nil end end
forward_definition(n = number_prefix_arg || 1)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 98 def forward_definition(n = number_prefix_arg || 1) tokens = Ripper.lex(@buffer.to_s) @buffer.forward_line n.times do |i| tokens = tokens.drop_while { |(l, _), e, t| l < @buffer.current_line || e != :on_kw || /\A(?:class|module|def)\z/ !~ t } (line,), = tokens.first if line.nil? @buffer.end_of_buffer break end @buffer.goto_line(line) tokens = tokens.drop(1) end while /\s/ =~ @buffer.char_after @buffer.forward_char end end
symbol_pattern()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 146 def symbol_pattern /[\p{Letter}\p{Number}_$@!?]/ end
toggle_test()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 162 def toggle_test case @buffer.file_name when %r'(.*)/test/(.*/)?test_(.*?)\.rb\z' path = find_test_target_path($1, $2, $3) find_file(path) when %r'(.*)/spec/(.*/)?(.*?)_spec\.rb\z' path = find_test_target_path($1, $2, $3) find_file(path) when %r'(.*)/(?:lib|app)/(.*/)?(.*?)\.rb\z' path = find_test_path($1, $2, $3) find_file(path) else raise EditorError, "Unknown file type" end end
Private Instance Methods
beginning_of_indentation()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 186 def beginning_of_indentation loop do @buffer.re_search_backward(INDENT_BEG_RE) space = @buffer.match_string(1) s = @buffer.substring(@buffer.point_min, @buffer.point) if PartialLiteralAnalyzer.in_literal?(s) next end return space_width(space) end rescue SearchError @buffer.beginning_of_buffer 0 end
calculate_indentation()
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 217 def calculate_indentation if @buffer.current_line == 1 return 0 end @buffer.save_excursion do @buffer.beginning_of_line start_with_period = @buffer.looking_at?(/[ \t]*\./) bol_pos = @buffer.point base_indentation = beginning_of_indentation start_pos = @buffer.point start_line = @buffer.current_line tokens = lex(@buffer.substring(start_pos, bol_pos)) _, event, text = tokens.last if event == :on_nl _, event, text = tokens[-2] end if event == :on_tstring_beg || event == :on_heredoc_beg || event == :on_regexp_beg || (event == :on_regexp_end && text.size > 1) || event == :on_tstring_content return nil end i, extra_end_count = find_nearest_beginning_token(tokens) (line, column), event, = i ? tokens[i] : nil if event == :on_lparen && tokens.dig(i + 1, 1) != :on_ignored_nl return column + 1 end if line @buffer.goto_line(start_line - 1 + line) while !@buffer.beginning_of_buffer? if @buffer.save_excursion { @buffer.backward_char @buffer.skip_re_backward(/\s/) @buffer.char_before == ?, } @buffer.backward_line else break end end @buffer.looking_at?(/[ \t]*/) base_indentation = space_width(@buffer.match_string(0)) end @buffer.goto_char(bol_pos) if line.nil? indentation = base_indentation - extra_end_count * @buffer[:indent_level] else indentation = base_indentation + @buffer[:indent_level] end if @buffer.looking_at?(/[ \t]*([}\])]|(end|else|elsif|when|in|rescue|ensure)\b)/) indentation -= @buffer[:indent_level] end _, last_event, last_text = tokens.reverse_each.find { |_, e, _| e != :on_sp && e != :on_nl && e != :on_ignored_nl } if start_with_period || (last_event == :on_op && last_text != "|") || (last_event == :on_kw && /\A(and|or)\z/.match?(last_text)) || last_event == :on_period || (last_event == :on_comma && event != :on_lbrace && event != :on_lparen && event != :on_lbracket) indentation += @buffer[:indent_level] end indentation end end
endless_method_def?(tokens, i)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 343 def endless_method_def?(tokens, i) ts = tokens.drop(i + 1) ts.shift while ts[0][1] == :on_sp _, event = ts.shift return false if event != :on_ident ts.shift while ts[0][1] == :on_sp if ts[0][1] == :on_lparen ts.shift count = 1 while count > 0 _, event = ts.shift return false if event.nil? case event when :on_lparen count +=1 when :on_rparen count -=1 end end ts.shift while ts[0][1] == :on_sp end ts[0][1] == :on_op && ts[0][2] == "=" rescue NoMethodError # no token return false end
find_first_path(patterns)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 389 def find_first_path(patterns) patterns.each do |pattern| paths = Dir.glob(pattern) return paths.first if !paths.empty? end nil end
find_nearest_beginning_token(tokens)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 293 def find_nearest_beginning_token(tokens) stack = [] (tokens.size - 1).downto(0) do |i| (line, ), event, text = tokens[i] case event when :on_kw _, prev_event, _ = tokens[i - 1] next if prev_event == :on_symbeg case text when "class", "module", "def", "if", "unless", "case", "do", "for", "while", "until", "begin" if /\A(if|unless|while|until)\z/.match?(text) && modifier?(tokens, i) next end if text == "def" && endless_method_def?(tokens, i) next end if stack.empty? return i end if stack.last != "end" raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}" end stack.pop when "end" stack.push(text) end when :on_rbrace, :on_rparen, :on_rbracket, :on_embexpr_end stack.push(text) when :on_lbrace, :on_lparen, :on_lbracket, :on_tlambeg, :on_embexpr_beg if stack.empty? return i end if stack.last != BLOCK_END[text] raise EditorError, "#{@buffer.name}:#{line}: Unmatched #{text}" end stack.pop end end return nil, stack.grep_v(/[)\]]/).size end
find_test_path(base, namespace, name)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 378 def find_test_path(base, namespace, name) patterns = [] if namespace patterns.push("#{base}/test/**/#{namespace}test_#{name}.rb") patterns.push("#{base}/spec/**/#{namespace}#{name}_spec.rb") end patterns.push("#{base}/test/**/test_#{name}.rb") patterns.push("#{base}/spec/**/#{name}_spec.rb") find_first_path(patterns) or raise EditorError, "Test not found" end
find_test_target_path(base, namespace, name)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 369 def find_test_target_path(base, namespace, name) patterns = [] if namespace patterns.push("#{base}/{lib,app}/**/#{namespace}#{name}.rb") end patterns.push("#{base}/{lib,app}/**/#{name}.rb") find_first_path(patterns) or raise EditorError, "Test target not found" end
lex(source)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 201 def lex(source) line_count = source.count("\n") s = source lineno = 1 tokens = [] loop do lexer = Ripper::Lexer.new(s, "-", lineno) tokens.concat(lexer.lex) last_line = tokens.dig(-1, 0, 0) return tokens if last_line.nil? || last_line >= line_count s = source.sub(/(.*\n?){#{last_line}}/, "") return tokens if last_line + 1 <= lineno lineno = last_line + 1 end end
modifier?(tokens, i)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 336 def modifier?(tokens, i) (line,), = tokens[i] ts = tokens[0...i].reverse_each.take_while { |(l,_),| l == line } t = ts.find { |_, e| e != :on_sp } t && !(t[1] == :on_op && t[2] == "=") end
space_width(s)
click to toggle source
# File lib/textbringer/modes/ruby_mode.rb, line 182 def space_width(s) s.gsub(/\t/, " " * @buffer[:tab_width]).size end