redcar 0.10 → 0.11.0dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. data/CHANGES +14 -0
  2. data/Rakefile +68 -29
  3. data/lib/redcar.rb +2 -2
  4. data/plugins/application/lib/application/dialogs/filter_list_dialog.rb +2 -1
  5. data/plugins/application_swt/spec/application_swt/gradient_spec.rb +3 -12
  6. data/plugins/core/lib/core/resource.rb +13 -5
  7. data/plugins/document_search/features/find.feature +366 -214
  8. data/plugins/document_search/features/incremental_search.feature +351 -0
  9. data/plugins/document_search/features/replace.feature +16 -16
  10. data/plugins/document_search/features/step_definitions/find_steps.rb +16 -0
  11. data/plugins/document_search/features/support/env.rb +11 -0
  12. data/plugins/document_search/lib/document_search.rb +149 -109
  13. data/plugins/document_search/lib/document_search/commands.rb +251 -202
  14. data/plugins/document_search/lib/document_search/find_speedbar.rb +138 -81
  15. data/plugins/document_search/lib/document_search/incremental_search_speedbar.rb +70 -0
  16. data/plugins/document_search/lib/document_search/query_options.rb +15 -39
  17. data/plugins/document_search/plugin.rb +1 -1
  18. data/plugins/edit_view/features/step_definitions/editing_steps.rb +6 -2
  19. data/plugins/edit_view_swt/lib/edit_view_swt.rb +2 -2
  20. data/plugins/file_parser/lib/file_parser.rb +6 -1
  21. data/plugins/html_view/features/step_definitions/web_view_steps.rb +12 -0
  22. data/plugins/html_view/features/support/env.rb +16 -0
  23. data/plugins/html_view/lib/html_view.rb +5 -1
  24. data/plugins/line_tools/lib/line_tools.rb +16 -0
  25. data/plugins/project/features/find_file.feature +28 -0
  26. data/plugins/project/features/open_and_save_files.feature +11 -0
  27. data/plugins/project/features/step_definitions/file_steps.rb +6 -1
  28. data/plugins/project/features/support/env.rb +2 -0
  29. data/plugins/project/lib/project.rb +49 -6
  30. data/plugins/project/lib/project/commands.rb +18 -6
  31. data/plugins/project/lib/project/find_file_dialog.rb +19 -8
  32. data/plugins/project/lib/project/find_recent_dialog.rb +30 -0
  33. data/plugins/project/lib/project/manager.rb +41 -10
  34. data/plugins/project/lib/project/recent.rb +64 -0
  35. data/plugins/project/spec/fixtures/myproject/vendor/bar.rb +0 -0
  36. data/plugins/project/spec/fixtures/myproject/vendor/plugins/bar.rb +0 -0
  37. data/plugins/{find-in-project → project_search}/TODO.md +3 -3
  38. data/plugins/project_search/features/support/env.rb +6 -0
  39. data/plugins/project_search/features/word_search.feature +34 -0
  40. data/plugins/project_search/lib/project_search.rb +73 -0
  41. data/plugins/project_search/lib/project_search/binary_data_detector.rb +46 -0
  42. data/plugins/project_search/lib/project_search/commands.rb +62 -0
  43. data/plugins/project_search/lib/project_search/hit.rb +17 -0
  44. data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/collapsed.png +0 -0
  45. data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/expanded.png +0 -0
  46. data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/spinner.gif +0 -0
  47. data/plugins/project_search/lib/project_search/lucene_index.rb +64 -0
  48. data/plugins/project_search/lib/project_search/lucene_refresh.rb +22 -0
  49. data/plugins/project_search/lib/project_search/project.rb +14 -0
  50. data/plugins/project_search/lib/project_search/query.rb +29 -0
  51. data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/stylesheets/style.css +14 -3
  52. data/plugins/project_search/lib/project_search/views/_file.html.erb +60 -0
  53. data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/views/index.html.erb +12 -9
  54. data/plugins/project_search/lib/project_search/word_search.rb +105 -0
  55. data/plugins/project_search/lib/project_search/word_search_controller.rb +207 -0
  56. data/plugins/project_search/plugin.rb +8 -0
  57. data/plugins/project_search/spec/fixtures/project/binary_file.bin +0 -0
  58. data/plugins/project_search/spec/fixtures/project/foo.txt +43 -0
  59. data/plugins/project_search/spec/fixtures/project/qux.rb +3 -0
  60. data/plugins/project_search/spec/project_search/binary_data_detector_spec.rb +24 -0
  61. data/plugins/project_search/spec/project_search/word_search_spec.rb +157 -0
  62. data/plugins/project_search/spec/spec_helper.rb +27 -0
  63. data/plugins/redcar/redcar.rb +77 -71
  64. data/plugins/ruby/lib/ruby/syntax_checker.rb +1 -1
  65. data/plugins/snippets/features/snippets.feature +12 -0
  66. data/plugins/snippets/lib/snippets/tab_handler.rb +1 -1
  67. metadata +46 -25
  68. data/plugins/document_search/features/find_and_replace.feature +0 -723
  69. data/plugins/document_search/lib/document_search/find_and_replace_speedbar.rb +0 -142
  70. data/plugins/find-in-project/lib/find_in_project.rb +0 -35
  71. data/plugins/find-in-project/lib/find_in_project/commands.rb +0 -30
  72. data/plugins/find-in-project/lib/find_in_project/controllers.rb +0 -170
  73. data/plugins/find-in-project/lib/find_in_project/views/_divider.html.erb +0 -4
  74. data/plugins/find-in-project/lib/find_in_project/views/_file_heading.html.erb +0 -10
  75. data/plugins/find-in-project/lib/find_in_project/views/_file_line.html.erb +0 -6
  76. data/plugins/find-in-project/plugin.rb +0 -11
  77. data/plugins/project/lib/project/recent_directories.rb +0 -54
@@ -1,142 +0,0 @@
1
- module DocumentSearch
2
- class FindAndReplaceSpeedbar < Redcar::Speedbar
3
- NotFoundMessage = 'Not found!'
4
-
5
- class << self
6
- attr_accessor :previous_replace
7
- end
8
- @@previous_replace = ''
9
-
10
- attr_accessor :initial_query
11
-
12
- def doc
13
- win = Redcar.app.focussed_window
14
- tab = win.focussed_notebook_tab
15
- tab.document if tab
16
- end
17
-
18
- ### UI ###
19
-
20
- # Override num_columns to control number of rows.
21
- def num_columns
22
- return 7
23
- end
24
-
25
- label :label_find, "Find:"
26
- textbox :query do
27
- if doc
28
- update_options_from_ui
29
- FindSpeedbar.find_incremental
30
- end
31
- end
32
-
33
- combo :query_type, ["Plain", "Regex", "Glob"], "Plain" do |val|
34
- FindSpeedbar.previous_options.query_type = QueryOptions.query_type_to_symbol(val)
35
- update_options_from_ui
36
- FindSpeedbar.find_incremental
37
- end
38
-
39
- toggle :match_case, 'Match case', nil, false do |val|
40
- FindSpeedbar.previous_options.match_case = val
41
- update_options_from_ui
42
- FindSpeedbar.find_incremental
43
- end
44
-
45
- toggle :wrap_around, 'Wrap around', nil, true do |val|
46
- FindSpeedbar.previous_options.wrap_around = val
47
- update_options_from_ui
48
- FindSpeedbar.find_incremental
49
- end
50
-
51
- label :label_not_found, NotFoundMessage # Hack: Set label for sizing, clear in after_draw
52
- label :label_space_end_row1, ""
53
- label :label_spacer_start_row2, ""
54
-
55
- label :label_replace, "Replace:"
56
- textbox :replace
57
-
58
- button :replace_find, 'Replace && Find', "Return" do
59
- update_options_from_ui
60
- FindAndReplaceSpeedbar.replace_and_find(
61
- FindSpeedbar.previous_query, FindAndReplaceSpeedbar.previous_replace, FindSpeedbar.previous_options) or not_found
62
- end
63
-
64
- button :replace_all, "Replace All", nil do
65
- update_options_from_ui
66
- FindAndReplaceSpeedbar.replace_all(
67
- FindSpeedbar.previous_query, FindAndReplaceSpeedbar.previous_replace, FindSpeedbar.previous_options) or not_found
68
- end
69
-
70
- label :label_spacer_mid_row2, ""
71
-
72
- button :find_previous, "Previous", nil do
73
- update_options_from_ui
74
- FindSpeedbar.find_previous or not_found
75
- end
76
-
77
- button :find_next, "Next", nil do
78
- update_options_from_ui
79
- FindSpeedbar.find_next or not_found
80
- end
81
-
82
- # Initializes UI elements.
83
- def after_draw
84
- clear_not_found
85
- self.query.value = @initial_query || FindSpeedbar.previous_query
86
- self.replace.value = FindAndReplaceSpeedbar.previous_replace || ""
87
- self.query_type.value = QueryOptions.query_type_to_text(FindSpeedbar.previous_options.query_type)
88
- self.match_case.value = FindSpeedbar.previous_options.match_case
89
- self.wrap_around.value = FindSpeedbar.previous_options.wrap_around
90
- self.query.edit_view.document.select_all
91
- end
92
-
93
- # Store options specified in the UI, to be called before executing a command.
94
- def update_options_from_ui
95
- clear_not_found
96
- FindSpeedbar.previous_query = query.value
97
- FindAndReplaceSpeedbar.previous_replace = replace.value
98
- FindSpeedbar.previous_options.query_type = QueryOptions.query_type_to_symbol(query_type.value)
99
- FindSpeedbar.previous_options.match_case = match_case.value
100
- FindSpeedbar.previous_options.wrap_around = wrap_around.value
101
- end
102
-
103
- # Sets the "Not found" label message, invoking the system beep.
104
- def not_found
105
- Swt::Widgets::Display.get_current.beep
106
- self.label_not_found.text = NotFoundMessage
107
- end
108
-
109
- # Clears the "Not found" label message.
110
- def clear_not_found
111
- self.label_not_found.text = ''
112
- end
113
-
114
- ### COMMANDS ###
115
-
116
- def self.repeat_find_next
117
- find_next(FindSpeedbar.previous_query, FindSpeedbar.previous_options) or not_found
118
- end
119
-
120
- def self.repeat_find_previous
121
- find_previous(FindSpeedbar.previous_query, FindSpeedbar.previous_options) or not_found
122
- end
123
-
124
- def self.replace_and_find(query, replace, options)
125
- cmd = ReplaceAndFindCommand.new(query, replace, options)
126
- cmd.run(:env => {:edit_view => Redcar::EditView.focussed_tab_edit_view})
127
- end
128
-
129
- def self.replace_all(query, replace, options)
130
- cmd = ReplaceAllCommand.new(query, replace, options)
131
- cmd.run(:env => {:edit_view => Redcar::EditView.focussed_tab_edit_view})
132
- end
133
-
134
- def self.use_selection_for_replace(doc, active_speedbar=nil)
135
- return unless doc.selection?
136
- FindAndReplaceSpeedbar.previous_replace = doc.selected_text
137
- if active_speedbar && (active_speedbar.instance_of? FindAndReplaceSpeedbar)
138
- active_speedbar.replace.value = FindAndReplaceSpeedbar.previous_replace
139
- end
140
- end
141
- end
142
- end
@@ -1,35 +0,0 @@
1
- require 'find_in_project/controllers'
2
- require 'find_in_project/commands'
3
-
4
- module Redcar
5
- class FindInProject
6
- def self.menus
7
- Redcar::Menu::Builder.build do
8
- sub_menu "Project" do
9
- item "Find in Project!", :command => Redcar::FindInProject::OpenSearch, :priority => 3
10
- end
11
- end
12
- end
13
-
14
- def self.toolbars
15
- ToolBar::Builder.build do
16
- item "Find in Project", :command => OpenSearch, :icon => File.join(Redcar::ICONS_DIRECTORY, "application-search-result.png"), :barname => :project
17
- end
18
- end
19
-
20
- def self.storage
21
- @storage ||= begin
22
- storage = Redcar::Plugin::Storage.new('find_in_project')
23
- storage.set_default('recent_queries', [])
24
- storage.set_default('excluded_dirs', ['.git', '.svn', '.redcar'])
25
- storage.set_default('excluded_files', [])
26
- storage.set_default('excluded_patterns', [/tags$/, /\.log$/])
27
- storage.set_default('literal_match', false)
28
- storage.set_default('match_case', false)
29
- storage.set_default('with_context', false)
30
- storage.set_default('context_lines', 2)
31
- storage.save
32
- end
33
- end
34
- end
35
- end
@@ -1,30 +0,0 @@
1
- module Redcar
2
- class FindInProject
3
- class OpenSearch < Redcar::Command
4
- sensitize :open_project
5
- def execute
6
- if Project::Manager.focussed_project
7
- if (tab = find_open_instance)
8
- tab.html_view.controller = tab.html_view.controller # refresh
9
- else
10
- tab = win.new_tab(Redcar::HtmlTab)
11
- tab.html_view.controller = Redcar::FindInProject::Controller.new
12
- end
13
- tab.focus
14
- else
15
- # warning
16
- Application::Dialog.message_box("You need an open project to be able to use Find In Project!", :type => :error)
17
- end
18
- end
19
-
20
- private
21
-
22
- def find_open_instance
23
- all_tabs = Redcar.app.focussed_window.notebooks.map { |nb| nb.tabs }.flatten
24
- all_tabs.find do |t|
25
- t.is_a?(Redcar::HtmlTab) && t.title == Redcar::FindInProject::Controller.new.title
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,170 +0,0 @@
1
- require 'erb'
2
- require 'cgi'
3
-
4
- module Redcar
5
- class FindInProject
6
- class Controller
7
- include Redcar::HtmlController
8
-
9
- def title
10
- "Find In Project"
11
- end
12
-
13
- def index
14
- @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
15
- @settings = Redcar::FindInProject.storage
16
- @query = doc.selected_text if doc && doc.selection?
17
- @literal_match = Redcar::FindInProject.storage['literal_match']
18
- @match_case = Redcar::FindInProject.storage['match_case']
19
- @with_context = Redcar::FindInProject.storage['with_context']
20
- render('index')
21
- end
22
-
23
- def search(query, literal_match, match_case, with_context)
24
- @query = query
25
- Redcar::FindInProject.storage['recent_queries'] = add_or_move_to_top(@query, Redcar::FindInProject.storage['recent_queries'])
26
- Redcar::FindInProject.storage['literal_match'] = (@literal_match = (literal_match == 'true'))
27
- Redcar::FindInProject.storage['match_case'] = (@match_case = (match_case == 'true'))
28
- Redcar::FindInProject.storage['with_context'] = (@with_context = (with_context == 'true'))
29
-
30
- execute("$('#cached_query').val(\"#{escape_javascript(@query)}\");")
31
- execute("$('#results').html(\"<div id='no_results'>Searching...</div>\");")
32
- execute("$('#spinner').show();")
33
- execute("$('#results_summary').hide();")
34
- execute("$('#file_results_count').html(0);")
35
- execute("$('#line_results_count').html(0);")
36
- search_in_background
37
-
38
- nil
39
- end
40
-
41
- def open_file(file, line, query, literal_match, match_case)
42
- Project::Manager.open_file(File.join(Project::Manager.focussed_project.path, file))
43
- doc.cursor_offset = doc.offset_at_line(line.to_i - 1)
44
- regexp_text = literal_match ? Regexp.escape(query) : query
45
- regex = match_case ? /(#{regexp_text})/ : /(#{regexp_text})/i
46
- index = doc.get_line(line.to_i - 1).index(regex)
47
- if index
48
- length = doc.get_line(line.to_i - 1).match(regex)[1].length
49
- doc.set_selection_range(doc.cursor_line_start_offset + index, doc.cursor_line_start_offset + index + length)
50
- end
51
- doc.scroll_to_line(line.to_i)
52
- nil
53
- end
54
-
55
- def preferences
56
- Redcar.app.make_sure_at_least_one_window_open # open a new window if needed
57
-
58
- Redcar::FindInProject.storage # populate the file if it isn't already
59
-
60
- tab = Redcar.app.focussed_window.new_tab(Redcar::EditTab)
61
- mirror = Project::FileMirror.new(File.join(Redcar.user_dir, "storage", "find_in_project.yaml"))
62
- tab.edit_view.document.mirror = mirror
63
- tab.edit_view.reset_undo
64
- tab.focus
65
- end
66
-
67
- def close
68
- Thread.kill(@thread) if @thread
69
- @thread = nil
70
- super
71
- end
72
-
73
- private
74
-
75
- def render(view)
76
- rhtml = ERB.new(File.read(File.join(File.dirname(__FILE__), "views", "#{view.to_s}.html.erb")))
77
- rhtml.result(binding)
78
- end
79
-
80
- def doc
81
- Redcar.app.focussed_window.focussed_notebook_tab.edit_view.document rescue false
82
- end
83
-
84
- def add_or_move_to_top(item, array)
85
- return array if item.strip.empty?
86
- array.delete_at(array.index(item)) if array.include?(item)
87
- array.unshift(item)
88
- end
89
-
90
- def search_in_background
91
- @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
92
- @settings = Redcar::FindInProject.storage
93
- @project_path = Project::Manager.focussed_project.path
94
-
95
- # kill any existing running search to prevent memory bloat
96
- Thread.kill(@thread) if @thread
97
- @thread = nil
98
-
99
- @thread = Thread.new do
100
- matched_lines = false
101
- last_matching_line = nil
102
-
103
- Redcar::FileParser.new(@project_path, @settings).each_line do |line|
104
- next unless matching_line?(line)
105
-
106
- # Add an initial <tr></tr> so that tr:last can be used
107
- execute("if ($('#results table').size() == 0) { $('#results').html(\"<table><tr></tr></table>\"); }")
108
- execute("if ($('#results_summary').first().is(':hidden')) { $('#results_summary').show(); }")
109
-
110
- parsing_new_file = (!last_matching_line || last_matching_line.file != line.file)
111
-
112
- if parsing_new_file
113
- execute("$('#file_results_count').html(parseInt($('#file_results_count').html()) + 1);")
114
- execute("$('#results table tr:last').after(\"<tr><td class='break' colspan='2'></td></tr>\");") if matched_lines
115
- @file = line.file
116
- execute("$('#results table tr:last').after(\"#{escape_javascript(render('_file_heading'))}\");")
117
- @line_index = 0 # reset line row styling
118
- end
119
-
120
- if @with_context && !parsing_new_file && (line.num - last_matching_line.num) > (@settings['context_lines'] * 2)
121
- execute("$('#results table tr:last').after(\"#{escape_javascript(render('_divider'))}\");")
122
- end
123
-
124
- context = line.context(@settings['context_lines']) if @with_context
125
- context[:before].each { |b_line| render_line(b_line) } if @with_context
126
- render_line(line)
127
- context[:after].each { |a_line| render_line(a_line) } if @with_context
128
-
129
- execute("$('#line_results_count').html(parseInt($('#line_results_count').html()) + 1);")
130
-
131
- matched_lines = true
132
- last_matching_line = line
133
- end
134
-
135
- if matched_lines
136
- # Remove the blank tr we added initially
137
- execute("$('#results table tr:first').remove();")
138
- else
139
- result = "<div id='no_results'>No results were found using the search terms you provided.</div>"
140
- execute("$('#results').html(\"#{escape_javascript(result)}\");")
141
- end
142
-
143
- execute("$('#spinner').hide();")
144
-
145
- Thread.kill(@thread) if @thread
146
- @thread = nil
147
- end
148
- end
149
-
150
- def matching_line?(line)
151
- regexp_text = @literal_match ? Regexp.escape(@query) : @query
152
- regexp = @match_case ? /#{regexp_text}/ : /#{regexp_text}/i
153
- line.text =~ regexp
154
- end
155
-
156
- def escape_javascript(text)
157
- escape_map = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'" }
158
- text.to_s.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { escape_map[$1] }
159
- end
160
-
161
- def render_line(line)
162
- @line_index += 1
163
- @line, @file = line, line.file
164
- execute("if ($('#results tr.file_#{@file.num}.line_#{@line.num}').size() == 0) {
165
- $('#results table tr:last').after(\"#{escape_javascript(render('_file_line'))}\");
166
- }")
167
- end
168
- end
169
- end
170
- end
@@ -1,4 +0,0 @@
1
- <tr class="divider file_<%= @line.file.num %>">
2
- <td class="line_num">. . .</td>
3
- <td class="text">&nbsp;</td> <!-- extra space to ensure line-height is respected -->
4
- </tr>
@@ -1,10 +0,0 @@
1
- <% image_path = File.expand_path(File.join(@plugin_root, %w(lib find_in_project images))) %>
2
-
3
- <tr>
4
- <td class="file_heading" colspan="2">
5
- <a class="expand_collapse" data-file_num="<%= @file.num %>">
6
- <img src="<%= image_path %>/expanded.png" />
7
- <%= CGI::escapeHTML(@file.name) %>
8
- </a>
9
- </td>
10
- </tr>
@@ -1,6 +0,0 @@
1
- <tr class="result file_<%= @file.num %> line_<%= @line.num %> <%= (@line_index % 2 == 0 ? 'even' : 'odd') %>" data-href='<%= CGI::escapeHTML(@file.name) %>' data-line_num='<%= @line.num %>'>
2
- <td class='line_num'><%= @line.num %></td>
3
- <% regexp_text = CGI.escapeHTML((@literal_match ? Regexp.escape(@query) : @query)) %>
4
- <% text = CGI.escapeHTML(@line.text).gsub((@match_case ? /(#{regexp_text})/ : /(#{regexp_text})/i)) { "<span>#{$1}</span>" } %>
5
- <td class='text'><%= text %>&nbsp;</td> <!-- extra space to ensure line-height is respected -->
6
- </tr>
@@ -1,11 +0,0 @@
1
- Plugin.define do
2
- name "find-in-project"
3
- version "0.1.0"
4
-
5
- object "Redcar::FindInProject"
6
- file "lib", "find_in_project"
7
-
8
- dependencies "core", ">0",
9
- "HTML View", ">=0.3.2",
10
- "file_parser", "=0.2.0"
11
- end
@@ -1,54 +0,0 @@
1
- module Redcar
2
- class Project
3
- # Purpose of this class is to have a menu that shows the 5 most recent opened directories
4
- # This way users can quickly go to directories they have recently opened, or use frequently
5
- class RecentDirectories
6
- MAX_LENGTH = 10
7
-
8
- # Create menus for recent directories
9
- def self.storage
10
- @storage ||= begin
11
- storage = Plugin::Storage.new('recent_directories')
12
- storage.set_default('list', [])
13
- storage
14
- end
15
- end
16
-
17
- def self.generate_menu(builder)
18
- directories = storage['list']
19
- directories.each do |dir|
20
- if File.directory?(File.expand_path(dir))
21
- builder.item(File.basename(dir)) do
22
- if File.directory?(File.expand_path(dir))
23
- Project::Manager.open_project_for_path(dir)
24
- else
25
- remove_path(dir)
26
- end
27
- end
28
- else
29
- remove_path(dir)
30
- end
31
- end
32
- end
33
-
34
- # Stores the given path to the text file, to appear in the recent directories menu.
35
- #
36
- # @param [String] path the path of a directory to be saved
37
- def self.store_path(path)
38
- path = File.expand_path(path)
39
- storage["list"].delete(path)
40
- storage["list"].unshift(path)
41
- if storage["list"].length == MAX_LENGTH + 1
42
- storage["list"].pop
43
- end
44
- storage.save
45
- end
46
-
47
- def self.remove_path(path)
48
- path = File.expand_path(path)
49
- storage["list"].delete(path)
50
- storage.save
51
- end
52
- end
53
- end
54
- end