module VER module Methods module SmartAutoindent def self.newline(text) if text.options.autoindent indented_newline(text) else Insert.newline(text) end end def self.newline_below(text) if text.options.autoindent text.mark_set('insert', 'insert lineend') newline(text) text.minor_mode(:control, :insert) else Insert.newline_below(text) end end def self.newline_above(text) Undo.record text do |record| if text.index(:insert).y > 1 Move.prev_line(text) newline_below(text) else record.insert('insert linestart', "\n") text.mark_set(:insert, 'insert - 1 line') Control.clean_line(text, 'insert - 1 line', record) text.minor_mode(:control, :insert) end end end def self.indented_newline(text, record = text) settings = indent_settings(text) increase, decrease = settings.values_at(:increase, :decrease) unless increase || decrease record.insert :insert, "\n" return end ref_line = text.get( "insert - 1 lines linestart", "insert - 1 lines lineend" ) ref = ref_line[/^\s*/].size / 2 ref_inc = increase ? ref_line.scan(increase).size : 0 ref_dec = decrease ? ref_line.scan(decrease).size : 0 cur_line = text.get( "insert linestart", "insert lineend" ) cur_inc = increase ? cur_line.scan(increase).size : 0 cur_dec = decrease ? cur_line.scan(decrease).size : 0 # we strip whitespace from previous empty lines, but it's still added to # the current one, so we use it as reference. if ref_line.empty? ref = cur_line[/^\s*/].size / 2 end pattern = [ if ref_inc != 0 && ref_dec != 0; '=' elsif ref_inc != 0; '+' elsif ref_dec != 0; '-' else; '?' end, if cur_inc != 0 && cur_dec != 0; '=' elsif cur_inc != 0; '+' elsif cur_dec != 0; '-' else; '?' end ].join cur_indent, next_indent = case pattern when '++'; [ref + 1, ref + 2] when '+-'; [ref, ref] when '+='; [ref, ref] when '+?'; [ref + 1, ref + 1] when '-+'; [ref, ref] when '--'; [ref - 1, ref - 2] when '-='; [ref, ref] when '-?'; [ref, ref] when '=+'; [ref + 1, ref + 1] when '=-'; [ref, ref] when '=='; [ref, ref] when '=?'; [ref + 1, ref + 1] when '?+'; [ref, ref + 1] when '?-'; [ref - 1, ref - 2] when '?='; [ref - 1, ref] when '??'; [ref, ref] end if text.index('insert - 1 line') == text.index('insert') # first line, replace is futile next_indent -= 1 elsif cur_line =~ /\S/ cur_indent = [0, cur_indent].max record.replace( 'insert linestart', 'insert lineend', (' ' * (cur_indent * 2)) << cur_line.lstrip ) else # that was an empty line record.replace('insert linestart', 'insert lineend', '') end next_indent = [0, next_indent].max record.insert('insert lineend', "\n#{' ' * (next_indent * 2)}") end def self.indent_settings(text) return {} unless text.load_preferences indent_settings = {} text.preferences.each do |pref| settings = pref[:settings] indent_settings[:increase] ||= settings[:increaseIndentPattern] indent_settings[:decrease] ||= settings[:decreaseIndentPattern] indent_settings[:indent_next] ||= settings[:indentNextLinePattern] indent_settings[:unindented] ||= settings[:unIndentedLinePattern] end [:increase, :decrease, :indent_next, :unindented].each do |key| if value = indent_settings[key] indent_settings[key] = Regexp.new(value) else indent_settings.delete(key) end end return indent_settings end end end case options.keymap when 'vim' minor_mode :control do handler Methods::SmartAutoindent map :newline_below, %w[o] map :newline_above, %w[O] end minor_mode :insert do handler Methods::SmartAutoindent map :newline, %w[Return] end end end