Class: Ruber::AutoEnd::Extension

Inherits:
Qt::Object
  • Object
show all
Includes:
Extension
Defined in:
plugins/auto_end/auto_end.rb

Overview

Extension object for the Auto End plugin

The procedure of inserting an end is split in two parts, performed in separate moments:

  1. finding out whether the current line needs an end inserted after it. This is done in response to the Document#text_inserted signal
  2. inserting the text. This is done in response to the Document#text_changed signal

The reason for this two-step behaviour is that Document#text_inserted is emitted multiple times in case of a Paste operation. Thus, inserting the end keywords in it would cause them to be added in the middle of the pasted text, which is wrong. What we do instead is to analyze each line in response to Document#text_inserted, storing the line position and the text to insert if appropriate, overwriting any other information so that only the last position is recorded. When all text has been processed, the document emits the Document#text_changed signal and, in response to this we insert the end keyword (if appropriate).

Defined Under Namespace

Classes: Insertion

Constant Summary

IDENTIFIER_PATTERN =

The regexp fragment which matches an identifier. In theory, this should just be \w+. However, from ruby 1.9.2, \w only matches ASCII characters, while identifiers can also contain unicode characters. To allow for this, the \p{Word} character class is used from ruby 1.9.2 onward, while \w is used for previous versions

RUBY_VERSION >= '1.9.2' ? '\p{Word}+' : '\w+'
MULTI_ID_PATTERN =

The regexp fragment which matches a multiple identifier (that is, an identifier maybe followed by several other identifiers separated by ::)

"#{IDENTIFIER_PATTERN}(?:::#{IDENTIFIER_PATTERN})*"
PATTERNS =

The patterns used to find out whether an end keyword should be inserted after a line.

Each entry is itself an array with three elements:

  • the regexp to match agains the line
  • the text to insert if the regexp match
  • an array with two elements, representing the position where the cursor should be moved to after the insertion, as described in Insertion#final_position
[
  [/^\s*if\s/, "\nend", [0, -1]],
  [/=\s*if\s/, "\nend", [0, -1]],
  [/^\s*unless\s/, "\nend", [0, -1]],
  [/=\s*unless\s/, "\nend", [0, -1]],
  [/\bdo\s*$/, "\nend", [0, -1]],
  [/\bdo\s+\|/, "\nend", [0, -1]],
  [/^\s*def\s/, "\nend", [0, -1]],
  [/\bclass\b/, "\nend", [0, -1]],
  [/\bmodule\b/, "\nend", [0, -1]],
  [/^\s*case\b/, "\nend", [0, -1]],
  [/=\s*case\b/, "\nend", [0, -1]],
  [/^\s*while\s/, "\nend", [0,-1]],
  [/^\s*until\s/, "\nend", [0,-1]],
  [/^=begin(\s|$)/, "\n=end", [0, -1]],
  [/^\s*begin\s/, "\nend", [0, -1]],
  [/(^=\s+|.=\s*)begin\s/, "\nend", [0, -1]],
  [/^\s*for\s/, "\nend", [0,-1]],
  [/=\s*for\s/, "\nend", [0,-1]]
]

Instance Attribute Summary

Attributes included from Extension

plugin

Instance Method Summary (collapse)

Methods included from Extension

#query_close, #save_settings, #shutdown

Constructor Details

- (Extension) initialize(prj)

A new instance of Extension

Parameters:



130
131
132
133
134
135
# File 'plugins/auto_end/auto_end.rb', line 130

def initialize prj
  super
  @doc = prj.document
  @insertion = nil
  connect_slots
end

Instance Method Details

- (nil) connect_slots (private)

Makes connections to the document’s signals

Returns:

  • (nil)


199
200
201
202
203
# File 'plugins/auto_end/auto_end.rb', line 199

def connect_slots
  connect @doc, SIGNAL('text_inserted(KTextEditor::Range, QObject*)'), self, SLOT('text_inserted(KTextEditor::Range)')
  connect @doc, SIGNAL('text_changed(QObject*)'), self, SLOT(:text_changed)
  nil
end

- (nil) disconnect_slots (private)

Disconnects connections to the document’s signals

Returns:

  • (nil)


209
210
211
212
# File 'plugins/auto_end/auto_end.rb', line 209

def disconnect_slots
  disconnect @doc, SIGNAL('text_inserted(KTextEditor::Range, QObject*)'), self, SLOT('text_inserted(KTextEditor::Range)')
  disconnect @doc, SIGNAL('text_changed(QObject*)'), self, SLOT(:text_changed)
end

- (Object) insert_text(insert_pos, lines, dest) (private)

Note:

nothing is done unless the active view (according to Document#active_view) is associated with the document

Inserts text at the given position and moves the cursor to the specified position

To avoid the possibility of infinite recursion, before inserting text #disconnect_slots is called. After the text has been inserted #connect_slots is called.

Parameters:



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'plugins/auto_end/auto_end.rb', line 227

def insert_text insert_pos, lines, dest
  view = @doc.active_view
  return unless view
  disconnect_slots
  replace_pos = KTextEditor::Cursor.new insert_pos.line, @doc.line_length(insert_pos.line)
  insert_pos.column = @doc.line_length insert_pos.line
  @doc.insert_text insert_pos, lines 
  final_pos = KTextEditor::Cursor.new insert_pos.line + lines.size - 1,
      lines[-1].size
  view.execute_action 'tools_align'
  dest_line = insert_pos.line+dest[0]
  dest_col = dest[1]
  dest_col += @doc.line_length(dest_line) + 1 if dest_col < 0
  view.go_to dest_line, dest_col
  connect_slots
end

- (nil) remove_from_project (private)

Override of #remove_from_project

Returns:

  • (nil)


191
192
193
# File 'plugins/auto_end/auto_end.rb', line 191

def remove_from_project
  disconnect_slots
end

- (nil) text_changed (private)

Slot called in response to the Document#text_changed signal

If there’s an insertion position memorized, inserts the corresponding text after the current line, then moves the cursor to the position stored with the insertion object.

The current insertion is forgotten.

Returns:

  • (nil)


178
179
180
181
182
183
184
# File 'plugins/auto_end/auto_end.rb', line 178

def text_changed
  if @insertion
    insert_text KTextEditor::Cursor.new(@insertion.line_number, 0), 
        @insertion.lines, @insertion.final_position
    @insertion = nil
  end
end

Slot Signature:

text_changed()

- (Object) text_inserted(range) (private)

Slot called when some text is inserted

If one of the recognized patterns match the current line, memorizes an Insertion object pointing to the current line and using the parameters associated with the matching pattern.

If the inserted text doesn’t end in a newline, nothing is done.

If the current line doesn’t match any pattern, the currently memorized insertion position (if any) is forgotten

Parameters:



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'plugins/auto_end/auto_end.rb', line 151

def text_inserted range
  return unless @doc.active?
  text = @doc.text range
  return unless text.end_with? "\n"
  @insertion = nil
  line = @doc.line( range.end.line - 1)
  pattern = PATTERNS.find{|pat| pat[0].match line}
  if pattern and !line.start_with? '#'
    check_res = @doc.extension(:syntax_checker).check_syntax(:format => false, 
        :update => false)
    return unless check_res
    errors = check_res[:errors]
    # Usually, missing end errors are the last ones to be reported
    if errors && !errors.empty? && errors[-1].error_type == :missing_end
#           indentation = line.match(/^\s*/)[0].size
#           next_indentation = @doc.line(range.end.line + 1).match(/^\s*/)[0].size
#           unless next_indentation > indentation
      @insertion = Insertion.new range.end.line, pattern[1], pattern[2]
    end
  end
  nil
end

Slot Signature:

text_inserted(KTextEditor::Range)