redcar 0.9.2 → 0.10

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 (234) hide show
  1. data/CHANGES +34 -4
  2. data/Rakefile +2 -1
  3. data/lib/redcar.rb +3 -3
  4. data/lib/redcar/installer.rb +2 -3
  5. data/plugins/application/features/step_definitions/dialog_steps.rb +7 -0
  6. data/plugins/application/features/step_definitions/key_steps.rb +18 -0
  7. data/plugins/application/features/step_definitions/menu_steps.rb +5 -6
  8. data/plugins/application/features/step_definitions/speedbar_steps.rb +29 -9
  9. data/plugins/application/features/step_definitions/tree_steps.rb +13 -0
  10. data/plugins/application/features/support/env.rb +39 -5
  11. data/plugins/application/features/support/fake_event.rb +12 -0
  12. data/plugins/application/lib/application.rb +5 -6
  13. data/plugins/application/lib/application/dialog.rb +53 -10
  14. data/plugins/application/lib/application/dialogs/modeless_list_dialog.rb +85 -0
  15. data/plugins/application/lib/application/keymap.rb +10 -8
  16. data/plugins/application/lib/application/menu.rb +38 -16
  17. data/plugins/application/lib/application/treebook.rb +30 -0
  18. data/plugins/application/lib/application/window.rb +20 -2
  19. data/plugins/application/spec/application/command/executor_spec.rb +1 -0
  20. data/plugins/application/spec/application/menu_spec.rb +26 -26
  21. data/plugins/application/spec/application/treebook_spec.rb +6 -6
  22. data/plugins/application/spec/spec_helper.rb +10 -1
  23. data/plugins/application_swt/lib/application_swt.rb +25 -3
  24. data/plugins/application_swt/lib/application_swt/dialog_adapter.rb +48 -27
  25. data/plugins/application_swt/lib/application_swt/dialogs/filter_list_dialog_controller.rb +22 -11
  26. data/plugins/application_swt/lib/application_swt/dialogs/modeless_dialog.rb +113 -0
  27. data/plugins/application_swt/lib/application_swt/dialogs/modeless_html_dialog.rb +85 -0
  28. data/plugins/application_swt/lib/application_swt/dialogs/modeless_list_dialog_controller.rb +143 -0
  29. data/plugins/application_swt/lib/application_swt/gradient.rb +61 -0
  30. data/plugins/application_swt/lib/application_swt/menu/binding_translator.rb +4 -4
  31. data/plugins/application_swt/lib/application_swt/notebook.rb +5 -8
  32. data/plugins/application_swt/lib/application_swt/speedbar.rb +1 -0
  33. data/plugins/application_swt/lib/application_swt/treebook.rb +6 -8
  34. data/plugins/application_swt/lib/application_swt/window.rb +85 -57
  35. data/plugins/application_swt/lib/swt/graphics_utils.rb +23 -0
  36. data/plugins/application_swt/lib/swt/vtab_folder.rb +7 -0
  37. data/plugins/application_swt/lib/swt/vtab_label.rb +1 -1
  38. data/plugins/application_swt/spec/application_swt/gradient_spec.rb +142 -0
  39. data/plugins/auto_completer/lib/auto_completer.rb +10 -42
  40. data/plugins/auto_completer/lib/auto_completer/list_dialog.rb +21 -0
  41. data/plugins/clojure/lib/clojure.rb +33 -0
  42. data/plugins/{repl/lib/repl/clojure_mirror.rb → clojure/lib/clojure/repl_mirror.rb} +16 -20
  43. data/plugins/clojure/plugin.rb +9 -0
  44. data/plugins/{repl/spec/repl/clojure_mirror_spec.rb → clojure/spec/clojure/repl_mirror_spec.rb} +12 -13
  45. data/plugins/clojure/spec/spec_helper.rb +5 -0
  46. data/plugins/{repl → clojure}/vendor/Wrapper.clj +0 -0
  47. data/plugins/{repl → clojure}/vendor/dummy +0 -0
  48. data/plugins/{repl → clojure}/vendor/enclojure-wrapper.jar +0 -0
  49. data/plugins/connection_manager/lib/connection_manager.rb +13 -13
  50. data/plugins/declarations/lib/declarations.rb +17 -6
  51. data/plugins/document_search/features/find.feature +389 -0
  52. data/plugins/document_search/features/find_and_replace.feature +723 -0
  53. data/plugins/document_search/features/replace.feature +69 -62
  54. data/plugins/document_search/lib/document_search.rb +81 -64
  55. data/plugins/document_search/lib/document_search/commands.rb +258 -0
  56. data/plugins/document_search/lib/document_search/find_and_replace_speedbar.rb +142 -0
  57. data/plugins/document_search/lib/document_search/find_speedbar.rb +102 -0
  58. data/plugins/document_search/lib/document_search/query_options.rb +45 -0
  59. data/plugins/edit_view/features/case_change.feature +9 -5
  60. data/plugins/edit_view/features/step_definitions/editing_steps.rb +19 -0
  61. data/plugins/edit_view/lib/edit_view.rb +15 -12
  62. data/plugins/edit_view/lib/edit_view/actions/arrow_keys.rb +12 -2
  63. data/plugins/edit_view/lib/edit_view/commands/text_conversion_commands.rb +1 -1
  64. data/plugins/edit_view/lib/edit_view/document.rb +129 -99
  65. data/plugins/edit_view_swt/lib/edit_view_swt.rb +33 -15
  66. data/plugins/encryption/encryption.rb +2 -0
  67. data/plugins/find-in-project/lib/find_in_project.rb +3 -5
  68. data/plugins/find-in-project/lib/find_in_project/views/index.html.erb +2 -0
  69. data/plugins/groovy/features/step_definitions/groovy_steps.rb +2 -2
  70. data/plugins/groovy/features/syntax_check_groovy.feature +3 -3
  71. data/plugins/groovy/lib/groovy.rb +38 -0
  72. data/plugins/groovy/lib/groovy/commands.rb +10 -0
  73. data/plugins/{repl/lib/repl/groovy_mirror.rb → groovy/lib/groovy/repl_mirror.rb} +33 -13
  74. data/plugins/groovy/lib/{syntax_check/groovy.rb → groovy/syntax_checker.rb} +13 -8
  75. data/plugins/groovy/plugin.rb +5 -4
  76. data/plugins/{repl/spec/repl/groovy_mirror_spec.rb → groovy/spec/groovy/repl_mirror_spec.rb} +14 -13
  77. data/plugins/groovy/spec/spec_helper.rb +5 -0
  78. data/plugins/html_view/assets/json2.js +476 -0
  79. data/plugins/html_view/lib/html_view.rb +1 -0
  80. data/plugins/java/features/fixtures/test.java +0 -0
  81. data/plugins/java/features/support/env.rb +27 -0
  82. data/plugins/java/features/syntax_check_java.feature +86 -0
  83. data/plugins/java/lib/syntax_check/java.rb +86 -0
  84. data/plugins/java/plugin.rb +7 -0
  85. data/plugins/javascript/features/fixtures/test2.js +5 -0
  86. data/plugins/javascript/features/step_definitions/javascript_steps.rb +16 -0
  87. data/plugins/javascript/features/support/env.rb +14 -0
  88. data/plugins/javascript/features/syntax_check_javascript.feature +46 -3
  89. data/plugins/javascript/lib/syntax_check/javascript.rb +15 -9
  90. data/plugins/line_tools/features/trim_line.feature +49 -0
  91. data/plugins/line_tools/lib/line_tools.rb +5 -1
  92. data/plugins/mirah/README +7 -0
  93. data/plugins/mirah/features/fixtures/test.mirah +2 -0
  94. data/plugins/mirah/features/syntax_check_mirah.feature +46 -0
  95. data/plugins/mirah/lib/mirah.rb +43 -0
  96. data/plugins/mirah/lib/mirah/my_error_handler.rb +22 -0
  97. data/plugins/mirah/lib/mirah/repl_mirror.rb +50 -0
  98. data/plugins/mirah/lib/mirah/syntax_checker.rb +38 -0
  99. data/plugins/mirah/plugin.rb +8 -0
  100. data/plugins/mirah/spec/mirah/repl_mirror_spec.rb +188 -0
  101. data/plugins/mirah/spec/spec_helper.rb +5 -0
  102. data/plugins/mirah/vendor/mirah-parser.jar +0 -0
  103. data/plugins/pair_highlighter/lib/pair_highlighter/document_controller.rb +24 -23
  104. data/plugins/plugin_manager_ui/lib/plugin_manager_ui.rb +10 -1
  105. data/plugins/plugin_manager_ui/views/index.html.erb +2 -0
  106. data/plugins/project/features/find_file.feature +40 -16
  107. data/plugins/project/features/highlight_focussed_tab.feature +16 -10
  108. data/plugins/project/features/step_definitions/find_file_steps.rb +11 -0
  109. data/plugins/project/features/step_definitions/project_tree_steps.rb +5 -1
  110. data/plugins/project/features/support/env.rb +5 -0
  111. data/plugins/project/lib/project/commands.rb +8 -1
  112. data/plugins/project/lib/project/dir_controller.rb +4 -1
  113. data/plugins/project/lib/project/find_file_dialog.rb +16 -12
  114. data/plugins/project/lib/project/manager.rb +30 -1
  115. data/plugins/project_search/vendor/lucene/CHANGELOG +147 -0
  116. data/plugins/project_search/vendor/lucene/CONTRIBUTORS +17 -0
  117. data/plugins/project_search/vendor/lucene/Gemfile +9 -0
  118. data/plugins/project_search/vendor/lucene/Gemfile.lock +33 -0
  119. data/plugins/project_search/vendor/lucene/LICENSE +19 -0
  120. data/plugins/project_search/vendor/lucene/README.rdoc +283 -0
  121. data/plugins/project_search/vendor/lucene/Rakefile +35 -0
  122. data/plugins/project_search/vendor/lucene/examples/active_model/serializers.rb +25 -0
  123. data/plugins/project_search/vendor/lucene/examples/active_model/validation.rb +26 -0
  124. data/plugins/project_search/vendor/lucene/examples/admin/Rakefile +4 -0
  125. data/plugins/project_search/vendor/lucene/examples/admin/admin.rb +29 -0
  126. data/plugins/project_search/vendor/lucene/examples/admin/public/jquery.js +4376 -0
  127. data/plugins/project_search/vendor/lucene/examples/admin/public/neo4j.css +153 -0
  128. data/plugins/project_search/vendor/lucene/examples/admin/public/neo_admin.js +18 -0
  129. data/plugins/project_search/vendor/lucene/examples/admin/spec/admin_spec.rb +26 -0
  130. data/plugins/project_search/vendor/lucene/examples/admin/views/index.erb +21 -0
  131. data/plugins/project_search/vendor/lucene/examples/filetree/README.rdoc +9 -0
  132. data/plugins/project_search/vendor/lucene/examples/filetree/app.rb +7 -0
  133. data/plugins/project_search/vendor/lucene/examples/filetree/batch.props +5 -0
  134. data/plugins/project_search/vendor/lucene/examples/filetree/features/step_definitions/add_steps.rb +121 -0
  135. data/plugins/project_search/vendor/lucene/examples/filetree/features/support/env.rb +30 -0
  136. data/plugins/project_search/vendor/lucene/examples/filetree/features/support/rspec_helper.rb +50 -0
  137. data/plugins/project_search/vendor/lucene/examples/filetree/features/treesizes.feature +19 -0
  138. data/plugins/project_search/vendor/lucene/examples/imdb/1_create_neo_db.rb +66 -0
  139. data/plugins/project_search/vendor/lucene/examples/imdb/2_index_db.rb +23 -0
  140. data/plugins/project_search/vendor/lucene/examples/imdb/README +12 -0
  141. data/plugins/project_search/vendor/lucene/examples/imdb/find_actors.rb +56 -0
  142. data/plugins/project_search/vendor/lucene/examples/imdb/install.sh +12 -0
  143. data/plugins/project_search/vendor/lucene/examples/imdb/model.rb +37 -0
  144. data/plugins/project_search/vendor/lucene/examples/railway/README +111 -0
  145. data/plugins/project_search/vendor/lucene/examples/railway/railnet-app.rb +31 -0
  146. data/plugins/project_search/vendor/lucene/examples/railway/railnet-data.rb +42 -0
  147. data/plugins/project_search/vendor/lucene/examples/rest/example.rb +41 -0
  148. data/plugins/project_search/vendor/lucene/examples/you_might_know/YouMightKnow.java +60 -0
  149. data/plugins/project_search/vendor/lucene/examples/you_might_know/all_simple_paths.rb +34 -0
  150. data/plugins/project_search/vendor/lucene/examples/you_might_know/nodes.rb +34 -0
  151. data/plugins/project_search/vendor/lucene/examples/you_might_know/you_might_know.rb +50 -0
  152. data/plugins/project_search/vendor/lucene/lib/lucene.rb +15 -0
  153. data/plugins/project_search/vendor/lucene/lib/lucene/config.rb +145 -0
  154. data/plugins/project_search/vendor/lucene/lib/lucene/document.rb +96 -0
  155. data/plugins/project_search/vendor/lucene/lib/lucene/field_info.rb +144 -0
  156. data/plugins/project_search/vendor/lucene/lib/lucene/hits.rb +54 -0
  157. data/plugins/project_search/vendor/lucene/lib/lucene/index.rb +267 -0
  158. data/plugins/project_search/vendor/lucene/lib/lucene/index_info.rb +146 -0
  159. data/plugins/project_search/vendor/lucene/lib/lucene/index_searcher.rb +157 -0
  160. data/plugins/project_search/vendor/lucene/lib/lucene/jars.rb +5 -0
  161. data/plugins/project_search/vendor/lucene/lib/lucene/query_dsl.rb +135 -0
  162. data/plugins/project_search/vendor/lucene/lib/lucene/transaction.rb +117 -0
  163. data/plugins/project_search/vendor/lucene/lib/lucene/version.rb +3 -0
  164. data/plugins/project_search/vendor/lucene/lucene.gemspec +23 -0
  165. data/plugins/project_search/vendor/lucene/spec/lucene/document_spec.rb +32 -0
  166. data/plugins/project_search/vendor/lucene/spec/lucene/field_info_spec.rb +70 -0
  167. data/plugins/project_search/vendor/lucene/spec/lucene/index_info_spec.rb +76 -0
  168. data/plugins/project_search/vendor/lucene/spec/lucene/index_spec.rb +643 -0
  169. data/plugins/project_search/vendor/lucene/spec/lucene/query_dsl_spec.rb +142 -0
  170. data/plugins/project_search/vendor/lucene/spec/lucene/sort_spec.rb +101 -0
  171. data/plugins/project_search/vendor/lucene/spec/lucene/spec_helper.rb +10 -0
  172. data/plugins/project_search/vendor/lucene/spec/lucene/transaction_spec.rb +118 -0
  173. data/plugins/redcar/features/alter_font_size.feature +25 -0
  174. data/plugins/redcar/features/step_definitions/font_steps.rb +34 -0
  175. data/plugins/redcar/redcar.rb +256 -43
  176. data/plugins/repl/features/command_editing.feature +55 -0
  177. data/plugins/repl/features/command_history.feature +75 -0
  178. data/plugins/repl/features/step_definitions/repl_steps.rb +17 -1
  179. data/plugins/repl/features/support/env.rb +24 -0
  180. data/plugins/repl/features/support/fake_repl.rb +16 -0
  181. data/plugins/repl/lib/repl.rb +17 -74
  182. data/plugins/repl/lib/repl/repl_command.rb +20 -0
  183. data/plugins/repl/lib/repl/repl_mirror.rb +168 -22
  184. data/plugins/repl/lib/repl/repl_tab.rb +131 -6
  185. data/plugins/repl/plugin.rb +1 -1
  186. data/plugins/repl/spec/repl/repl_mirror_spec.rb +72 -0
  187. data/plugins/repl/spec/spec_helper.rb +1 -1
  188. data/plugins/repl_swt/lib/repl_swt.rb +7 -0
  189. data/plugins/repl_swt/lib/repl_swt/key_listener.rb +43 -0
  190. data/plugins/repl_swt/plugin.rb +8 -0
  191. data/plugins/ruby/lib/ruby.rb +35 -0
  192. data/plugins/{repl/lib/repl/ruby_mirror.rb → ruby/lib/ruby/repl_mirror.rb} +12 -12
  193. data/plugins/ruby/lib/{syntax_check/ruby.rb → ruby/syntax_checker.rb} +3 -3
  194. data/plugins/ruby/plugin.rb +5 -4
  195. data/plugins/{repl/spec/repl/ruby_mirror_spec.rb → ruby/spec/ruby/repl_mirror_spec.rb} +38 -29
  196. data/plugins/ruby/spec/spec_helper.rb +5 -0
  197. data/plugins/runnables/lib/runnables.rb +2 -0
  198. data/plugins/runnables/lib/runnables/command_output_controller.rb +5 -0
  199. data/plugins/runnables/lib/runnables/output_processor.rb +14 -3
  200. data/plugins/runnables/views/command_output.html.erb +3 -2
  201. data/plugins/scm/lib/scm.rb +4 -2
  202. data/plugins/scm/lib/scm/diff_mirror.rb +6 -6
  203. data/plugins/scm_git/lib/scm_git.rb +136 -107
  204. data/plugins/scm_git/lib/scm_git/change.rb +28 -19
  205. data/plugins/snippets/lib/snippets/explorer.rb +2 -2
  206. data/plugins/swt/lib/swt/full_swt.rb +1 -0
  207. data/plugins/syntax_check/features/step_definitions/syntax_check_steps.rb +4 -0
  208. data/plugins/syntax_check/features/support/env.rb +3 -0
  209. data/plugins/syntax_check/lib/syntax_check.rb +71 -5
  210. data/plugins/syntax_check/lib/syntax_check/annotation.rb +61 -0
  211. data/plugins/test_runner/lib/test_runner.rb +39 -0
  212. data/plugins/test_runner/lib/test_runner/rspec_runner.rb +20 -0
  213. data/plugins/test_runner/lib/test_runner/run_test_command.rb +63 -0
  214. data/plugins/test_runner/lib/test_runner/runnable_test_runner.rb +26 -0
  215. data/plugins/test_runner/plugin.rb +8 -0
  216. data/plugins/test_runner/spec/run_test_command_spec.rb +51 -0
  217. data/plugins/test_runner/spec/spec_helper.rb +5 -0
  218. data/plugins/textmate/lib/textmate.rb +12 -2
  219. data/plugins/textmate/vendor/redcar-bundles/Bundles/HTML.tmbundle/Syntaxes/HTML.plist +0 -2
  220. data/plugins/textmate/vendor/redcar-bundles/Bundles/Mirah.tmbundle/Syntaxes/Mirah.plist +22 -0
  221. data/plugins/textmate/vendor/redcar-bundles/Bundles/Mirah.tmbundle/info.plist +12 -0
  222. data/plugins/textmate/vendor/redcar-bundles/Bundles/Ruby.tmbundle/Syntaxes/Ruby.plist +2 -0
  223. data/plugins/todo_list/lib/todo_list.rb +7 -0
  224. data/plugins/todo_list/lib/todo_list/todo_controller.rb +3 -1
  225. data/plugins/tree/lib/tree.rb +4 -0
  226. data/plugins/tree_view_swt/lib/tree_view_swt.rb +5 -0
  227. data/plugins/web_bookmarks/lib/web_bookmarks.rb +10 -0
  228. metadata +137 -22
  229. data/plugins/document_search/features/search.feature +0 -163
  230. data/plugins/document_search/lib/document_search/replace_all_command.rb +0 -27
  231. data/plugins/document_search/lib/document_search/replace_command.rb +0 -38
  232. data/plugins/document_search/lib/document_search/replace_next_command.rb +0 -27
  233. data/plugins/document_search/lib/document_search/search_and_replace.rb +0 -81
  234. data/plugins/ruby/README +0 -6
@@ -8,73 +8,71 @@ Feature: Replace in file
8
8
  Scenario: Open replace speedbar
9
9
  When I replace the contents with "Foo\nBar\nBaz"
10
10
  And I move the cursor to 0
11
- And I run the command DocumentSearch::SearchAndReplaceCommand
12
- Then the DocumentSearch::SearchAndReplaceSpeedbar speedbar should be open
11
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
12
+ Then the DocumentSearch::FindAndReplaceSpeedbar speedbar should be open
13
13
 
14
14
  Scenario: Replace next occurrence on the same line
15
15
  When I replace the contents with "Foo\nBar Rab Rab\nBaz"
16
16
  And I move the cursor to 4
17
- And I run the command DocumentSearch::SearchAndReplaceCommand
18
- And I type "Rab" into the "Search" field in the speedbar
17
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
18
+ And I type "Rab" into the "Find" field in the speedbar
19
19
  And I type "RABBIT" into the "Replace" field in the speedbar
20
- And I press "Replace" in the speedbar
20
+ And I press "Replace && Find" in the speedbar
21
21
  Then the contents should be "Foo\nBar RABBIT Rab\nBaz"
22
- And the selected text should be "RABBIT"
23
- And the selection range should be from 8 to 14
22
+ And the selected text should be "Rab"
23
+ And the selection range should be from 15 to 18
24
24
 
25
25
  Scenario: Replace next occurrence on the same line twice
26
26
  When I replace the contents with "Foo\nBar Rab Rab\nBaz"
27
27
  And I move the cursor to 4
28
- And I run the command DocumentSearch::SearchAndReplaceCommand
29
- And I type "Rab" into the "Search" field in the speedbar
28
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
29
+ And I type "Rab" into the "Find" field in the speedbar
30
30
  And I type "RAB" into the "Replace" field in the speedbar
31
- And I press "Replace" in the speedbar
32
- And I press "Replace" in the speedbar
31
+ And I press "Replace && Find" in the speedbar
32
+ And I press "Replace && Find" in the speedbar
33
33
  Then the contents should be "Foo\nBar RAB RAB\nBaz"
34
34
  And the selected text should be "RAB"
35
- And the selection range should be from 12 to 15
35
+ And the selection range should be from 8 to 11
36
36
 
37
37
  Scenario: Replace next occurrence
38
38
  When I replace the contents with "Foo\nBar\nBaz\nBar\nQux"
39
39
  And I move the cursor to 0
40
- And I run the command DocumentSearch::SearchAndReplaceCommand
41
- And I type "Bar" into the "Search" field in the speedbar
40
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
41
+ And I type "Bar" into the "Find" field in the speedbar
42
42
  And I type "Rab" into the "Replace" field in the speedbar
43
- And I press "Replace" in the speedbar
43
+ And I press "Replace && Find" in the speedbar
44
44
  Then the contents should be "Foo\nRab\nBaz\nBar\nQux"
45
- And the selected text should be "Rab"
46
- And the selection should be on line 1
45
+ And the selected text should be "Bar"
46
+ And the selection should be on line 3
47
47
 
48
48
  Scenario: Replace next occurrence twice
49
49
  When I replace the contents with "Foo\nBar\nBaz\nBar\nQux"
50
50
  And I move the cursor to 0
51
- And I run the command DocumentSearch::SearchAndReplaceCommand
52
- And I type "Bar" into the "Search" field in the speedbar
51
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
52
+ And I type "Bar" into the "Find" field in the speedbar
53
53
  And I type "Rab" into the "Replace" field in the speedbar
54
- And I press "Replace" in the speedbar
54
+ And I press "Replace && Find" in the speedbar
55
55
  Then the contents should be "Foo\nRab\nBaz\nBar\nQux"
56
- When I press "Replace" in the speedbar
56
+ When I press "Replace && Find" in the speedbar
57
57
  Then the contents should be "Foo\nRab\nBaz\nRab\nQux"
58
- And the selected text should be "Rab"
59
- And the selection should be on line 3
58
+ And there should not be any text selected
60
59
 
61
60
  Scenario: Replace next occurrence wraps
62
61
  When I replace the contents with "Foo\nBar\nBaz"
63
62
  And I move the cursor to 8
64
- And I run the command DocumentSearch::SearchAndReplaceCommand
65
- And I type "Bar" into the "Search" field in the speedbar
63
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
64
+ And I type "Bar" into the "Find" field in the speedbar
66
65
  And I type "Rab" into the "Replace" field in the speedbar
67
- When I press "Replace" in the speedbar
66
+ When I press "Replace && Find" in the speedbar
68
67
  Then the contents should be "Foo\nRab\nBaz"
69
- And the selected text should be "Rab"
68
+ And there should not be any text selected
70
69
 
71
70
  Scenario: Replace all replaces one
72
71
  When I replace the contents with "Foo\nBar\nBaz"
73
72
  And I move the cursor to 0
74
- And I run the command DocumentSearch::SearchAndReplaceCommand
75
- And I type "Bar" into the "Search" field in the speedbar
73
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
74
+ And I type "Bar" into the "Find" field in the speedbar
76
75
  And I type "Rab" into the "Replace" field in the speedbar
77
- Then I should see a message box containing "Replaced 1 occurrence"
78
76
  When I press "Replace All" in the speedbar
79
77
  Then the contents should be "Foo\nRab\nBaz"
80
78
  And the selected text should be "Rab"
@@ -83,10 +81,9 @@ Feature: Replace in file
83
81
  Scenario: Replace all replaces two
84
82
  When I replace the contents with "Foo\nBar\nBaz\nBar\nQux"
85
83
  And I move the cursor to 0
86
- And I run the command DocumentSearch::SearchAndReplaceCommand
87
- And I type "Bar" into the "Search" field in the speedbar
84
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
85
+ And I type "Bar" into the "Find" field in the speedbar
88
86
  And I type "Rab" into the "Replace" field in the speedbar
89
- Then I should see a message box containing "Replaced 2 occurrences"
90
87
  When I press "Replace All" in the speedbar
91
88
  Then the contents should be "Foo\nRab\nBaz\nRab\nQux"
92
89
  And the selected text should be "Rab"
@@ -94,69 +91,79 @@ Feature: Replace in file
94
91
 
95
92
  Scenario: Replace all replaces two on the same line
96
93
  When I replace the contents with "abcabc"
97
- And I run the command DocumentSearch::SearchAndReplaceCommand
98
- And I type "bc" into the "Search" field in the speedbar
94
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
95
+ And I type "bc" into the "Find" field in the speedbar
99
96
  And I type "xx" into the "Replace" field in the speedbar
100
- Then I should see a message box containing "Replaced 2 occurrences"
101
97
  When I press "Replace All" in the speedbar
102
98
  Then the contents should be "axxaxx"
103
99
 
104
100
  Scenario: Replace all replaces overlapping occurences on the same line
105
101
  When I replace the contents with "deedeedeed"
106
- And I run the command DocumentSearch::SearchAndReplaceCommand
107
- And I type "deed" into the "Search" field in the speedbar
102
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
103
+ And I type "deed" into the "Find" field in the speedbar
108
104
  And I type "misdeed" into the "Replace" field in the speedbar
109
- Then I should see a message box containing "Replaced 2 occurrences"
110
105
  When I press "Replace All" in the speedbar
111
106
  Then the contents should be "misdeedeemisdeed"
112
107
 
108
+ Scenario: Replace all is a single undo action
109
+ When I replace the contents with "abcabc"
110
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
111
+ And I type "bc" into the "Find" field in the speedbar
112
+ And I type "xx" into the "Replace" field in the speedbar
113
+ When I press "Replace All" in the speedbar
114
+ Then the contents should be "axxaxx"
115
+ When I undo
116
+ Then the contents should be "abcabc"
117
+
113
118
  Scenario: Replace next occurrence test bug
114
119
  When I replace the contents with "the\n* Speedbars have access to the properties of the widgets in them."
115
120
  And I move the cursor to 0
116
- And I run the command DocumentSearch::SearchAndReplaceCommand
117
- And I type "the" into the "Search" field in the speedbar
121
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
122
+ And I type "the" into the "Find" field in the speedbar
118
123
  And I type "THE" into the "Replace" field in the speedbar
119
- And I press "Replace" in the speedbar
124
+ And I press "Replace && Find" in the speedbar
120
125
  Then the contents should be "THE\n* Speedbars have access to the properties of the widgets in them."
121
- And the selection range should be from 0 to 3
122
- And I press "Replace" in the speedbar
123
- Then the contents should be "THE\n* Speedbars have access to THE properties of the widgets in them."
124
126
  And the selection range should be from 31 to 34
125
- And I press "Replace" in the speedbar
126
- Then the contents should be "THE\n* Speedbars have access to THE properties of THE widgets in them."
127
+ And I press "Replace && Find" in the speedbar
128
+ Then the contents should be "THE\n* Speedbars have access to THE properties of the widgets in them."
127
129
  And the selection range should be from 49 to 52
128
- And I press "Replace" in the speedbar
129
- Then the contents should be "THE\n* Speedbars have access to THE properties of THE widgets in THEm."
130
+ And I press "Replace && Find" in the speedbar
131
+ Then the contents should be "THE\n* Speedbars have access to THE properties of THE widgets in them."
130
132
  And the selection range should be from 64 to 67
133
+ And I press "Replace && Find" in the speedbar
134
+ Then the contents should be "THE\n* Speedbars have access to THE properties of THE widgets in THEm."
135
+ And the selected text should be "THE"
136
+ And the selection should be on line 0
131
137
 
132
138
  Scenario: Replace regex with back-references
133
139
  When I replace the contents with "Curry chicken"
134
140
  And I move the cursor to 0
135
- And I run the command DocumentSearch::SearchAndReplaceCommand
136
- And I type "(\w+) chicken" into the "Search" field in the speedbar
141
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
142
+ And I choose "Regex" in the "query_type" field in the speedbar
143
+ And I type "(\w+) chicken" into the "Find" field in the speedbar
137
144
  And I type "\1 beef" into the "Replace" field in the speedbar
138
- And I press "Replace" in the speedbar
145
+ And I press "Replace && Find" in the speedbar
139
146
  Then the contents should be "Curry beef"
140
147
 
141
148
  Scenario: Replace should move past the current replacement if the query is a substring of the replacement
142
149
  When I replace the contents with "foo\nfoo\nfoo"
143
150
  And I move the cursor to 0
144
- And I run the command DocumentSearch::SearchAndReplaceCommand
145
- And I type "foo" into the "Search" field in the speedbar
151
+ And I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
152
+ And I type "foo" into the "Find" field in the speedbar
146
153
  And I type "foobar" into the "Replace" field in the speedbar
147
- And I press "Replace" in the speedbar
148
- And I press "Replace" in the speedbar
149
- And I press "Replace" in the speedbar
154
+ And I press "Replace && Find" in the speedbar
155
+ And I press "Replace && Find" in the speedbar
156
+ And I press "Replace && Find" in the speedbar
150
157
  Then the contents should be "foobar\nfoobar\nfoobar"
151
- And the selection range should be from 14 to 20
158
+ And the selected text should be "foo"
159
+ And the selection should be on line 0
152
160
 
153
161
  Scenario: The Search-and-Replace Speedbar should get initialized with the currently selected text
154
162
  When I replace the contents with "Foo\nBar\nFoo"
155
163
  And I select from 4 to 7
156
- When I run the command DocumentSearch::SearchAndReplaceCommand
157
- Then the "Search" field in the speedbar should have text "Bar"
164
+ When I run the command DocumentSearch::FindAndReplaceSpeedbarCommand
165
+ Then the "Find" field in the speedbar should have text "Bar"
158
166
  When I type "Foo" into the "Replace" field in the speedbar
159
- And I press "Replace" in the speedbar
167
+ And I press "Replace && Find" in the speedbar
160
168
  Then the contents should be "Foo\nFoo\nFoo"
161
169
 
162
-
@@ -1,103 +1,113 @@
1
1
  require 'strscan'
2
- require "document_search/replace_command"
3
- require "document_search/replace_all_command"
4
- require "document_search/replace_next_command"
5
- require "document_search/search_and_replace"
2
+ require "document_search/query_options"
3
+ require "document_search/commands"
4
+ require "document_search/find_speedbar"
5
+ require "document_search/find_and_replace_speedbar"
6
6
 
7
7
  module DocumentSearch
8
8
  def self.menus
9
9
  Redcar::Menu::Builder.build do
10
10
  sub_menu "Edit" do
11
- sub_menu "Search", :priority => 50 do
12
- item "Document Search", SearchForwardCommand
13
- item "Repeat Last Search", RepeatPreviousSearchForwardCommand
14
- item "Search and Replace", SearchAndReplaceCommand
11
+ sub_menu "Find", :priority => 50 do
12
+ item "Incremental Search", FindMenuCommand
13
+ item "Find...", FindAndReplaceSpeedbarCommand
14
+ separator
15
+ item "Find Next", FindNextMenuCommand
16
+ item "Find Previous", FindPreviousMenuCommand
17
+ item "Replace and Find", ReplaceAndFindMenuCommand
18
+ separator
19
+ item "Use Selection for Find", UseSelectionForFindMenuCommand
20
+ item "Use Selection for Replace", UseSelectionForReplaceMenuCommand
15
21
  end
16
22
  separator
17
23
  end
18
24
  end
19
25
  end
20
26
 
21
- def self.toolbars
22
- Redcar::ToolBar::Builder.build do
23
- item "Search Document", :command => DocumentSearch::SearchForwardCommand, :icon => File.join(Redcar::ICONS_DIRECTORY, "magnifier.png"), :barname => :edit
24
- item "Repeat Last Search", :command => DocumentSearch::RepeatPreviousSearchForwardCommand, :icon => File.join(Redcar::ICONS_DIRECTORY, "magnifier--arrow.png"), :barname => :edit
27
+ def self.keymaps
28
+ osx = Redcar::Keymap.build("main", :osx) do
29
+ link "Ctrl+S", DocumentSearch::FindMenuCommand
30
+ link "Cmd+F", DocumentSearch::FindAndReplaceSpeedbarCommand
31
+ link "Cmd+G", DocumentSearch::FindNextMenuCommand
32
+ link "Cmd+Shift+G", DocumentSearch::FindPreviousMenuCommand
33
+ link "Cmd+Alt+F", DocumentSearch::ReplaceAndFindMenuCommand
34
+ link "Cmd+E", DocumentSearch::UseSelectionForFindMenuCommand
35
+ link "Cmd+Shift+E", DocumentSearch::UseSelectionForReplaceMenuCommand
25
36
  end
26
- end
27
37
 
28
- class SearchSpeedbar < Redcar::Speedbar
29
- class << self
30
- attr_accessor :previous_query
31
- attr_accessor :previous_is_regex
32
- attr_accessor :previous_match_case
38
+ linwin = Redcar::Keymap.build("main", [:linux, :windows]) do
39
+ link "Alt+S", DocumentSearch::FindMenuCommand
40
+ link "Ctrl+F", DocumentSearch::FindAndReplaceSpeedbarCommand
41
+ link "Ctrl+G", DocumentSearch::FindNextMenuCommand
42
+ link "Ctrl+Shift+G", DocumentSearch::FindPreviousMenuCommand
43
+ link "Ctrl+E", DocumentSearch::UseSelectionForFindMenuCommand
44
+ link "Alt+E", DocumentSearch::UseSelectionForReplaceMenuCommand
33
45
  end
34
46
 
35
- attr_accessor :initial_query
47
+ [linwin, osx]
48
+ end
36
49
 
37
- def after_draw
38
- SearchSpeedbar.previous_query ||= ""
39
- self.query.value = @initial_query || SearchSpeedbar.previous_query
40
- self.is_regex.value = SearchSpeedbar.previous_is_regex
41
- self.match_case.value = SearchSpeedbar.previous_match_case
42
- self.query.edit_view.document.select_all
50
+ def self.toolbars
51
+ Redcar::ToolBar::Builder.build do
52
+ item "Find", :command => DocumentSearch::FindMenuCommand, :icon => File.join(Redcar::ICONS_DIRECTORY, "magnifier.png"), :barname => :edit
53
+ item "Find Next", :command => DocumentSearch::FindNextMenuCommand, :icon => File.join(Redcar::ICONS_DIRECTORY, "magnifier--arrow.png"), :barname => :edit
43
54
  end
55
+ end
44
56
 
45
- label :label, "Search:"
46
- textbox :query
47
-
48
- toggle :is_regex, 'Regex', nil, false do |v|
49
- # v is true or false
50
- SearchSpeedbar.previous_is_regex = v
57
+ class FindMenuCommand < Redcar::EditTabCommand
58
+ def execute
59
+ @speedbar = FindSpeedbar.new
60
+ if doc.selection?
61
+ @speedbar.initial_query = doc.selected_text
62
+ end
63
+ win.open_speedbar(@speedbar)
51
64
  end
65
+ end
52
66
 
53
- toggle :match_case, 'Match case', nil, false do |v|
54
- SearchSpeedbar.previous_match_case = v
67
+ class FindAndReplaceSpeedbarCommand < Redcar::EditTabCommand
68
+ def execute
69
+ @speedbar = FindAndReplaceSpeedbar.new
70
+ if doc.selection?
71
+ @speedbar.initial_query = doc.selected_text
72
+ end
73
+ win.open_speedbar(@speedbar)
55
74
  end
75
+ end
56
76
 
57
- button :search, "Search", "Return" do
58
- SearchSpeedbar.previous_query = query.value
59
- SearchSpeedbar.previous_match_case = match_case.value
60
- SearchSpeedbar.previous_is_regex = is_regex.value
61
- success = SearchSpeedbar.repeat_query
77
+ class FindNextMenuCommand < Redcar::EditTabCommand
78
+ def execute
79
+ FindSpeedbar.find_next
62
80
  end
81
+ end
63
82
 
64
- def self.repeat_query
65
- current_query = @previous_query
66
- if !@previous_is_regex
67
- current_query = Regexp.escape(current_query)
68
- end
69
- cmd = FindNextRegex.new(Regexp.new(current_query, !@previous_match_case), true)
70
- cmd.run_in_focussed_tab_edit_view
83
+ class FindPreviousMenuCommand < Redcar::EditTabCommand
84
+ def execute
85
+ FindSpeedbar.find_previous
71
86
  end
72
87
  end
73
88
 
74
- class SearchForwardCommand < Redcar::EditTabCommand
75
-
89
+ class ReplaceAndFindMenuCommand < Redcar::EditTabCommand
76
90
  def execute
77
- @speedbar = SearchSpeedbar.new
78
- if doc.selection?
79
- @speedbar.initial_query = doc.selected_text
80
- end
81
- win.open_speedbar(@speedbar)
91
+ FindAndReplaceSpeedbar.replace_and_find(
92
+ FindSpeedbar.previous_query,
93
+ FindAndReplaceSpeedbar.previous_replace,
94
+ FindSpeedbar.previous_options)
82
95
  end
83
96
  end
84
97
 
85
- class RepeatPreviousSearchForwardCommand < Redcar::EditTabCommand
98
+ class UseSelectionForFindMenuCommand < Redcar::EditTabCommand
86
99
  def execute
87
- SearchSpeedbar.repeat_query
100
+ FindSpeedbar.use_selection_for_find(doc, win.speedbar)
88
101
  end
89
102
  end
90
103
 
91
- class SearchAndReplaceCommand < Redcar::EditTabCommand
104
+ class UseSelectionForReplaceMenuCommand < Redcar::EditTabCommand
92
105
  def execute
93
- @speedbar = SearchAndReplaceSpeedbar.new
94
- if doc.selection?
95
- @speedbar.initial_query = doc.selected_text
96
- end
97
- win.open_speedbar(@speedbar)
106
+ FindAndReplaceSpeedbar.use_selection_for_replace(doc, win.speedbar)
98
107
  end
99
108
  end
100
109
 
110
+ # TODO(yozhipozhi): Figure out if this is still needed.
101
111
  class FindNextRegex < Redcar::DocumentCommand
102
112
  def initialize(re, wrap=nil)
103
113
  @re = re
@@ -110,8 +120,8 @@ module DocumentSearch
110
120
 
111
121
  def execute
112
122
  position = doc.cursor_offset
113
- sc = StringScanner.new(doc.get_all_text)
114
- sc.pos = position
123
+ sc = StringScanner.new(doc.get_all_text)
124
+ sc.pos = position
115
125
  sc.scan_until(@re)
116
126
 
117
127
  if @wrap and !sc.matched?
@@ -123,12 +133,19 @@ module DocumentSearch
123
133
  if sc.matched?
124
134
  endoff = sc.pos
125
135
  startoff = sc.pos - sc.matched_size
136
+ line = doc.line_at_offset(startoff)
137
+ lineoff = startoff - doc.offset_at_line(line)
138
+ if lineoff < doc.smallest_visible_horizontal_index
139
+ horiz = lineoff
140
+ else
141
+ horiz = endoff - doc.offset_at_line(line)
142
+ end
126
143
  doc.set_selection_range(sc.pos, sc.pos - sc.matched_size)
127
- doc.scroll_to_line(doc.line_at_offset(startoff))
144
+ doc.scroll_to_line(line)
145
+ doc.scroll_to_horizontal_offset(horiz) if horiz
128
146
  return true
129
147
  end
130
148
  false
131
149
  end
132
150
  end
133
-
134
151
  end
@@ -0,0 +1,258 @@
1
+ module DocumentSearch
2
+ # Utilities for extended search commands.
3
+ module FindCommandMixin
4
+ ### QUERY PATTERNS ###
5
+
6
+ # An instance of a search type method: Regular expression
7
+ def query_regex(query, options)
8
+ Regexp.new(query, !options.match_case)
9
+ end
10
+
11
+ # An instance of a search type method: Plain text search
12
+ def query_plain(query, options)
13
+ query_regex(Regexp.escape(query), options)
14
+ end
15
+
16
+ # An instance of a search type method: Glob text search
17
+ # Converts a glob pattern (* or ?) into a regex pattern
18
+ def query_glob(query, options)
19
+ # convert the glob pattern to a regex pattern
20
+ new_query = ""
21
+ query.each_char do |c|
22
+ case c
23
+ when "*"
24
+ new_query << ".*"
25
+ when "?"
26
+ new_query << "."
27
+ else
28
+ new_query << Regexp.escape(c)
29
+ end
30
+ end
31
+ query_regex(new_query, options)
32
+ end
33
+
34
+ ### SELECTION ###
35
+
36
+ # Selects the first match of query, starting from the start_pos.
37
+ def select_next_match(doc, start_pos, query, wrap_around)
38
+ scanner = StringScanner.new(doc.get_all_text)
39
+ scanner.pos = start_pos
40
+ if not scanner.scan_until(query)
41
+ if not wrap_around
42
+ return false
43
+ end
44
+
45
+ scanner.reset
46
+ if not scanner.scan_until(query)
47
+ return false
48
+ end
49
+ end
50
+
51
+ selection_pos = scanner.pos - scanner.matched_size
52
+ select_range(selection_pos, scanner.pos)
53
+ true
54
+ end
55
+
56
+ # Selects the match that first precedes the search position.
57
+ #
58
+ # The current implementation is brain-dead, but works: the document is scanned from the start
59
+ # up to the search position, retaining the most recent match. Many smarter, but more
60
+ # complicated strategies are possible; the best would be full reversal of the query regex, but
61
+ # that obviously has a lot of tricky aspects to it.
62
+ def select_previous_match(doc, search_pos, query, wrap_around)
63
+ previous_match = nil
64
+ scanner = StringScanner.new(doc.get_all_text)
65
+ scanner.pos = 0
66
+ while scanner.scan_until(query)
67
+ start_pos = scanner.pos - scanner.matched_size
68
+ if start_pos < search_pos
69
+ previous_match = [start_pos, scanner.pos]
70
+ elsif previous_match
71
+ select_range(*previous_match)
72
+ return true
73
+ elsif not wrap_around
74
+ return false
75
+ else
76
+ break
77
+ end
78
+ end
79
+
80
+ # Find the last match in the document.
81
+ while scanner.scan_until(query)
82
+ start_pos = scanner.pos - scanner.matched_size
83
+ previous_match = [start_pos, scanner.pos]
84
+ end
85
+
86
+ if previous_match
87
+ select_range(*previous_match)
88
+ return true
89
+ else
90
+ return false
91
+ end
92
+ end
93
+
94
+ # Replaces the current selection, if it matches the query completely.
95
+ def replace_selection_if_match(doc, start_pos, query, replace)
96
+ scanner = StringScanner.new(doc.selected_text)
97
+ scanner.check(query)
98
+ if (not scanner.matched?) || (scanner.matched_size != doc.selected_text.length)
99
+ return 0
100
+ end
101
+ matched_text = doc.get_range(start_pos, scanner.matched_size)
102
+ replacement_text = matched_text.gsub(query, replace)
103
+ doc.replace(start_pos, scanner.matched_size, replacement_text)
104
+ replacement_text.length
105
+ end
106
+
107
+ # Selects the specified range and scrolls to the start.
108
+ def select_range(start, stop)
109
+ line = doc.line_at_offset(start)
110
+ lineoff = start - doc.offset_at_line(line)
111
+ if lineoff < doc.smallest_visible_horizontal_index
112
+ horiz = lineoff
113
+ else
114
+ horiz = stop - doc.offset_at_line(line)
115
+ end
116
+ doc.set_selection_range(start, stop)
117
+ doc.scroll_to_line(line)
118
+ doc.scroll_to_horizontal_offset(horiz) if horiz
119
+ end
120
+ end
121
+
122
+
123
+ # Base class for find commands.
124
+ class FindCommandBase < Redcar::DocumentCommand
125
+ include FindCommandMixin
126
+
127
+ attr_reader :query
128
+
129
+ # description here
130
+ def initialize(query, options)
131
+ @options = options
132
+ @query = send(options.query_type, query, options)
133
+ end
134
+ end
135
+
136
+
137
+ # Finds the next match after the current location.
138
+ class FindIncrementalCommand < FindCommandBase
139
+ def execute
140
+ offsets = [doc.cursor_offset, doc.selection_offset]
141
+ start_pos = offsets.min
142
+ if select_next_match(doc, start_pos, query, @options.wrap_around)
143
+ true
144
+ else
145
+ # Clear selection as visual feedback that search failed.
146
+ doc.set_selection_range(start_pos, start_pos)
147
+ false
148
+ end
149
+ end
150
+ end
151
+
152
+
153
+ # Finds the next match after the current location.
154
+ class FindNextCommand < FindCommandBase
155
+ def execute
156
+ offsets = [doc.cursor_offset, doc.selection_offset]
157
+ start_pos = offsets.max
158
+ if select_next_match(doc, start_pos, query, @options.wrap_around)
159
+ true
160
+ else
161
+ # Clear selection as visual feedback that search failed.
162
+ doc.set_selection_range(start_pos, start_pos)
163
+ false
164
+ end
165
+ end
166
+ end
167
+
168
+
169
+ # Finds the previous match before the current location.
170
+ class FindPreviousCommand < FindCommandBase
171
+ def execute
172
+ offsets = [doc.cursor_offset, doc.selection_offset]
173
+ start_pos = offsets.min
174
+ if select_previous_match(doc, start_pos, query, @options.wrap_around)
175
+ true
176
+ else
177
+ # Clear selection as visual feedback that search failed.
178
+ doc.set_selection_range(start_pos, start_pos)
179
+ false
180
+ end
181
+ end
182
+ end
183
+
184
+
185
+ # Base class for replace commands.
186
+ class ReplaceCommandBase < Redcar::DocumentCommand
187
+ include FindCommandMixin
188
+
189
+ attr_reader :query, :replace
190
+
191
+ # description here
192
+ def initialize(query, replace, options)
193
+ @options = options
194
+ @query = send(options.query_type, query, options)
195
+ @replace = replace
196
+ end
197
+ end
198
+
199
+
200
+ # Replaces the currently selected text, if it matches the search criteria, then finds and
201
+ # selects the next match in the document.
202
+ #
203
+ # This command maintains the invariant that no text is replaced without first being selected, so
204
+ # the user always knows exactly what change is about to be made. A ramification of this policy
205
+ # is that, if no text is selected beforehand, or the selected text does not match the query,
206
+ # then "replace" portion of "replace and find" is essentially skipped, so that two button
207
+ # presses are required.
208
+ class ReplaceAndFindCommand < ReplaceCommandBase
209
+ def execute
210
+ offsets = [doc.cursor_offset, doc.selection_offset]
211
+ start_pos = offsets.min
212
+ if doc.selected_text.length > 0
213
+ chars_replaced = replace_selection_if_match(doc, start_pos, query, replace)
214
+ if chars_replaced > 0
215
+ start_pos += chars_replaced
216
+ else
217
+ start_pos = offsets.max
218
+ end
219
+ end
220
+ if select_next_match(doc, start_pos, query, @options.wrap_around)
221
+ true
222
+ else
223
+ # Clear selection as visual feedback that search failed.
224
+ doc.set_selection_range(start_pos, start_pos)
225
+ false
226
+ end
227
+ end
228
+ end
229
+
230
+
231
+ # Replaces all query matches.
232
+ class ReplaceAllCommand < ReplaceCommandBase
233
+ def execute
234
+ startoff, endoff = nil
235
+ text = doc.get_all_text
236
+ count = 0
237
+ sc = StringScanner.new(text)
238
+ while sc.scan_until(query)
239
+ count += 1
240
+
241
+ startoff = sc.pos - sc.matched_size
242
+ replacement_text = text.slice(startoff, sc.matched_size).gsub(query, replace)
243
+ endoff = startoff + replacement_text.length
244
+
245
+ text[startoff...sc.pos] = replacement_text
246
+ sc.string = text
247
+ sc.pos = startoff + replacement_text.length
248
+ end
249
+ if count > 0
250
+ doc.text = text
251
+ select_range(startoff + replacement_text.length, startoff)
252
+ true
253
+ else
254
+ false
255
+ end
256
+ end
257
+ end
258
+ end