redcar 0.10 → 0.11.0dev

Sign up to get free protection for your applications and to get access to all the features.
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