Class: Redcar::FilterListDialog

Inherits:
Object
  • Object
show all
Includes:
Model, Observable
Defined in:
plugins/application/lib/application/dialogs/filter_list_dialog.rb

Overview

A type of dialog containing a textbox and a list, where the list can be updated based on the contents of the textbox. For example, the Find File dialog box in the Project plugin.

Subclasses should implement the 'update_list' method and the 'selected' method.

Direct Known Subclasses

Application::OpenTreeFinderCommand::TreeFuzzyFilter, Declarations::OutlineViewDialog, Declarations::ProjectOutlineViewDialog, Declarations::SelectTagDialog, EditView::ChangeLanguageCommand::ChangeLanguageDialog, EditView::SelectFontDialog, EditView::SelectThemeDialog, Project::FindFileDialog, Project::FindRecentDialog, Snippets::Explorer

Constant Summary

Constant Summary

Constants included from Observable

Observable::ASPECTS

Instance Attribute Summary

Attributes included from Model

#controller

Instance Method Summary (collapse)

Methods included from Observable

#add_listener, #notify_listeners, #remove_listener

Methods included from ReentryHelpers

#ignore, #ignore_changes

Constructor Details

- (FilterListDialog) initialize

A new instance of FilterListDialog



11
12
13
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 11

def initialize
  self.controller = Redcar.gui.controller_for(self).new(self)
end

Instance Method Details

- (Object) close



19
20
21
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 19

def close
  notify_listeners(:close)
end

- (Object) filter_and_rank_by(list, query, max_length = 20)

Helper method for fuzzily filtering a list

Parameters:

  • list (Array<A>)

    the list to filter

  • query (String)

    the fuzzy string to match on

  • max_length (Integer) (defaults to: 20)

    the length of the resulting list (default 20)



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 67

def filter_and_rank_by(list, query, max_length=20)
  re = make_regex(query)
  ranked_list = []
  cutoff = 100000000
  results = list.each do |element|
    begin
      match_data = (block_given? ? yield(element) : element).match(re)
      if match_data
        captures = []
        match_data.captures.each_with_index do |_, i|
          i += 1 # Match group 0 is actually the complete regex, we are interested in the subgroups
          previous_capture = captures.last
          if previous_capture and match_data.begin(i) - previous_capture[:end] <= 1
            # If the the current match starts where the previous match ended, or they even overlap, merge the matches
            captures.last[:end] = match_data.end(i)
          else
            # Record the match
            captures << {:begin => match_data.begin(i), :end => match_data.end(i)}
          end
        end
        if captures.first[:begin] < cutoff
          # The penalty is calculated as such: The values of the beginnings of matches are penalty, the lengths are bonuses
          # This way, matching early and continiously is rewarded. Matching late in a word or only at intervals is punished.
          penalty = captures.inject(0) {|p,c| p + c[:begin] - (c[:end] - c[:begin]) }
          ranked_list << {:penalty => penalty, :first_match => captures.first[:begin], :element => element}
          ranked_list = ranked_list.sort_by {|a| a[:penalty] }

          # Performance optimization: Once we reach the maximum length, remove elements (saves later sorting)
          # Set the new cutoff to the beginning of the previously last element, to avoid later elements getting
          # into the list which would have an even worse rank.
          if ranked_list.length > max_length
            cutoff = ranked_list.last[:first_match]
            ranked_list.pop
          end
        end
      end
    rescue Errno::ENOENT
      # File.directory? can throw no such file or directory even if File.exist?
      # has returned true. For example this happens on some awful textmate filenames
      # unicode in them.
    end
  end
  ranked_list.map {|a| a[:element] }
end

- (Object) moved_to(item, ix)

Called by the controller when the user moves through the list.

Parameters:

  • the (String)

    list row text that is now highlighted

  • the (Integer)

    index of the row that is now highlighted



57
58
59
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 57

def moved_to(item, ix)
  # Override with the code you wish you had
end

- (Object) open



15
16
17
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 15

def open
  notify_listeners(:open)
end

- (Object) selected(item, ix)

Called by the controller when the user selects a row in the list.

Parameters:

  • the (String or Hash)

    item selected by the user

  • the (Integer)

    index of the row in the list selected by the user



49
50
51
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 49

def selected(item, ix)
  puts "Hooray! You selected #{text} at index #{ix}"
end

- (Boolean) step?

Returns:

  • (Boolean)


118
119
120
121
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 118

def step?
  @last_step ||= Time.now - step_time
  @last_step + step_time <= Time.now
end

- (Object) step_time

The time interval in seconds in which moved_to events are ignored Override to select different interval



114
115
116
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 114

def step_time
  1
end

- (Array<String> or Array<Hash>) update_list(filter)

Called by the controller when the user changes the filter.

Should return either a list of strings, or a list of hashes, which must have at least the key :name set, and may also have the key :image.

E.g. it returns [“feed.rb”, “application_controller.rb”] or it returns [=> “feed.rb”, => “application_controller.rb”]

The methods selected and moved_to will be called with items from this list.

Parameters:

  • the (String)

    filter entered by the user

Returns:

  • (Array<String> or Array<Hash>)

    the new list to display



35
36
37
38
39
40
41
42
43
# File 'plugins/application/lib/application/dialogs/filter_list_dialog.rb', line 35

def update_list(filter)
  if filter == ""
    %w(foo bar baz qux quux corge)
  else
    a = []
    5.times {|i| a << filter + " " + i.to_s }
    a
  end
end