xiki 0.5.0a

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 (252) hide show
  1. data/Gemfile +11 -0
  2. data/LICENSE +22 -0
  3. data/README.markdown +83 -0
  4. data/Rakefile +8 -0
  5. data/bin/xiki +46 -0
  6. data/etc/command/xiki_command.rb +203 -0
  7. data/etc/command/xiki_process.rb +52 -0
  8. data/etc/command/xiki_wrapper +2 -0
  9. data/etc/js/menu1.js +55 -0
  10. data/etc/js/xiki.js +259 -0
  11. data/etc/logo.png +0 -0
  12. data/etc/presentations/bootstrap.deck +5 -0
  13. data/etc/presentations/databases.deck +41 -0
  14. data/etc/presentations/diffs.deck +23 -0
  15. data/etc/presentations/documentation.deck +14 -0
  16. data/etc/presentations/effects.deck +5 -0
  17. data/etc/presentations/face.deck +297 -0
  18. data/etc/presentations/files.deck +79 -0
  19. data/etc/presentations/icons.deck +22 -0
  20. data/etc/presentations/images.deck +24 -0
  21. data/etc/presentations/key_shortcuts.deck +16 -0
  22. data/etc/presentations/macros.deck +18 -0
  23. data/etc/presentations/menu_classes.deck +44 -0
  24. data/etc/presentations/menu_directories.deck +30 -0
  25. data/etc/presentations/notes.deck +19 -0
  26. data/etc/presentations/other_languages.deck +55 -0
  27. data/etc/presentations/other_wiki_syntaxes.deck +4 -0
  28. data/etc/presentations/piano.deck +5 -0
  29. data/etc/presentations/potential/diffs.deck +38 -0
  30. data/etc/presentations/potential/evolution.deck +18 -0
  31. data/etc/presentations/potential/intro.deck +711 -0
  32. data/etc/presentations/potential/intro1.deck +711 -0
  33. data/etc/presentations/potential/intro2.deck +97 -0
  34. data/etc/presentations/potential/make_mysql_menu.deck +36 -0
  35. data/etc/presentations/potential/ruby_development.deck +17 -0
  36. data/etc/presentations/potential/ui_prototyping.deck +50 -0
  37. data/etc/presentations/potential/web_dev.deck +4 -0
  38. data/etc/presentations/potential/web_development.deck +10 -0
  39. data/etc/presentations/potential/wiki.deck +45 -0
  40. data/etc/presentations/presentations.deck +24 -0
  41. data/etc/presentations/rails_development.deck +29 -0
  42. data/etc/presentations/search_key_shortcuts.deck +37 -0
  43. data/etc/presentations/simplest_possible_ui.deck +37 -0
  44. data/etc/presentations/svg.deck +5 -0
  45. data/etc/presentations/testing.deck +28 -0
  46. data/etc/presentations/the_end.deck +13 -0
  47. data/etc/presentations/type_something_and_double_click.deck +57 -0
  48. data/etc/presentations/type_the_acronym.deck +144 -0
  49. data/etc/presentations/web_browser.deck +56 -0
  50. data/etc/presentations/xiki_command.deck +20 -0
  51. data/etc/presentations/xiki_url.deck +14 -0
  52. data/etc/shark.icns +0 -0
  53. data/etc/shark_script.icns +0 -0
  54. data/etc/snippets/html.notes +7 -0
  55. data/etc/snippets/notes.notes +20 -0
  56. data/etc/snippets/rb.notes +38 -0
  57. data/etc/templates/menu_template.menu +2 -0
  58. data/etc/templates/menu_template.rb +8 -0
  59. data/etc/templates/template.rb +5 -0
  60. data/etc/themes/Dark_Metal.notes +28 -0
  61. data/etc/themes/Orange_Path.notes +15 -0
  62. data/etc/themes/Shiny_Blue.notes +27 -0
  63. data/etc/themes/Shiny_Green.notes +27 -0
  64. data/etc/wrappers/wrapper.js +17 -0
  65. data/etc/wrappers/wrapper.py +20 -0
  66. data/etc/wrappers/wrapper.rb +25 -0
  67. data/lib/block.rb +72 -0
  68. data/lib/bookmarks.rb +352 -0
  69. data/lib/buffers.rb +170 -0
  70. data/lib/clipboard.rb +333 -0
  71. data/lib/code.rb +860 -0
  72. data/lib/code_tree.rb +476 -0
  73. data/lib/color.rb +274 -0
  74. data/lib/console.rb +557 -0
  75. data/lib/control_lock.rb +9 -0
  76. data/lib/control_tab.rb +176 -0
  77. data/lib/core_ext.rb +31 -0
  78. data/lib/cursor.rb +111 -0
  79. data/lib/deletes.rb +65 -0
  80. data/lib/diff_log.rb +297 -0
  81. data/lib/effects.rb +145 -0
  82. data/lib/environment.rb +5 -0
  83. data/lib/file_tree.rb +1875 -0
  84. data/lib/files.rb +334 -0
  85. data/lib/hide.rb +259 -0
  86. data/lib/history.rb +286 -0
  87. data/lib/image.rb +51 -0
  88. data/lib/incrementer.rb +15 -0
  89. data/lib/insert.rb +7 -0
  90. data/lib/irc.rb +22 -0
  91. data/lib/key_bindings.rb +658 -0
  92. data/lib/keys.rb +754 -0
  93. data/lib/launcher.rb +1351 -0
  94. data/lib/line.rb +429 -0
  95. data/lib/links.rb +6 -0
  96. data/lib/location.rb +175 -0
  97. data/lib/macros.rb +48 -0
  98. data/lib/man.rb +19 -0
  99. data/lib/menu.rb +708 -0
  100. data/lib/merb.rb +259 -0
  101. data/lib/message.rb +5 -0
  102. data/lib/meths.rb +56 -0
  103. data/lib/mode.rb +34 -0
  104. data/lib/move.rb +248 -0
  105. data/lib/notes.rb +1000 -0
  106. data/lib/numbers.rb +45 -0
  107. data/lib/ol.rb +203 -0
  108. data/lib/ol_helper.rb +44 -0
  109. data/lib/overlay.rb +167 -0
  110. data/lib/pause_means_space.rb +68 -0
  111. data/lib/php.rb +22 -0
  112. data/lib/projects.rb +21 -0
  113. data/lib/relinquish_exception.rb +2 -0
  114. data/lib/remote.rb +206 -0
  115. data/lib/requirer.rb +46 -0
  116. data/lib/rest_tree.rb +108 -0
  117. data/lib/ruby.rb +57 -0
  118. data/lib/ruby_console.rb +165 -0
  119. data/lib/search.rb +1572 -0
  120. data/lib/search_term.rb +40 -0
  121. data/lib/snippet.rb +68 -0
  122. data/lib/specs.rb +229 -0
  123. data/lib/styles.rb +274 -0
  124. data/lib/svn.rb +682 -0
  125. data/lib/text_util.rb +110 -0
  126. data/lib/tree.rb +1871 -0
  127. data/lib/tree_cursor.rb +87 -0
  128. data/lib/trouble_shooting.rb +27 -0
  129. data/lib/url_tree.rb +11 -0
  130. data/lib/view.rb +1474 -0
  131. data/lib/window.rb +133 -0
  132. data/lib/xiki.rb +404 -0
  133. data/menus/accounts.rb +5 -0
  134. data/menus/address_book.rb +21 -0
  135. data/menus/agenda.rb +28 -0
  136. data/menus/all.rb +5 -0
  137. data/menus/amazon.rb +16 -0
  138. data/menus/app.rb +16 -0
  139. data/menus/applescript.rb +46 -0
  140. data/menus/as.rb +15 -0
  141. data/menus/bookmarklet.rb +63 -0
  142. data/menus/bootstrap.rb +568 -0
  143. data/menus/browse.rb +13 -0
  144. data/menus/browser.rb +78 -0
  145. data/menus/cassandra_db.rb +36 -0
  146. data/menus/chmod.rb +27 -0
  147. data/menus/classes.rb +5 -0
  148. data/menus/coffee_script.rb +35 -0
  149. data/menus/computer.rb +24 -0
  150. data/menus/contacts.rb +5 -0
  151. data/menus/cookies.rb +25 -0
  152. data/menus/couch.rb +184 -0
  153. data/menus/crop.rb +45 -0
  154. data/menus/css.rb +55 -0
  155. data/menus/current.rb +5 -0
  156. data/menus/db.rb +12 -0
  157. data/menus/deck.rb +219 -0
  158. data/menus/dictionary.rb +9 -0
  159. data/menus/dir.rb +8 -0
  160. data/menus/disk.rb +5 -0
  161. data/menus/do.rb +13 -0
  162. data/menus/docs.rb +58 -0
  163. data/menus/dotsies.rb +107 -0
  164. data/menus/edited.rb +18 -0
  165. data/menus/emacs.rb +17 -0
  166. data/menus/enter.rb +13 -0
  167. data/menus/eval.rb +17 -0
  168. data/menus/executable.rb +16 -0
  169. data/menus/filter.rb +46 -0
  170. data/menus/firefox.rb +607 -0
  171. data/menus/foo.rb +30 -0
  172. data/menus/french.rb +7 -0
  173. data/menus/git.rb +185 -0
  174. data/menus/gito.rb +785 -0
  175. data/menus/google.rb +35 -0
  176. data/menus/google_images.rb +11 -0
  177. data/menus/google_patents.rb +10 -0
  178. data/menus/gutenberg.rb +13 -0
  179. data/menus/head.rb +10 -0
  180. data/menus/headings.rb +39 -0
  181. data/menus/html.rb +61 -0
  182. data/menus/icon.rb +40 -0
  183. data/menus/images.menu +2 -0
  184. data/menus/img.rb +15 -0
  185. data/menus/info.rb +9 -0
  186. data/menus/ip.rb +10 -0
  187. data/menus/iterm.rb +36 -0
  188. data/menus/itunes.rb +78 -0
  189. data/menus/javascript.rb +74 -0
  190. data/menus/layout.rb +18 -0
  191. data/menus/local_storage.rb +67 -0
  192. data/menus/ls.rb +19 -0
  193. data/menus/mac.rb +87 -0
  194. data/menus/maps.rb +18 -0
  195. data/menus/matches.rb +18 -0
  196. data/menus/memcache.rb +117 -0
  197. data/menus/mkdir.rb +23 -0
  198. data/menus/mongo.rb +83 -0
  199. data/menus/mysql.rb +294 -0
  200. data/menus/node.rb +88 -0
  201. data/menus/open.rb +19 -0
  202. data/menus/outline.rb +24 -0
  203. data/menus/piano.rb +746 -0
  204. data/menus/postgres.rb +34 -0
  205. data/menus/pre.rb +5 -0
  206. data/menus/python.rb +39 -0
  207. data/menus/rails.rb +160 -0
  208. data/menus/rake.rb +12 -0
  209. data/menus/redmine.rb +168 -0
  210. data/menus/riak_tree.rb +204 -0
  211. data/menus/rss.rb +15 -0
  212. data/menus/safari.rb +11 -0
  213. data/menus/sass.rb +15 -0
  214. data/menus/say.rb +6 -0
  215. data/menus/scale.rb +49 -0
  216. data/menus/serve.rb +78 -0
  217. data/menus/shuffle.rb +24 -0
  218. data/menus/spanish.rb +7 -0
  219. data/menus/standalone.rb +57 -0
  220. data/menus/tail.rb +41 -0
  221. data/menus/technologies.rb +19 -0
  222. data/menus/themes.rb +32 -0
  223. data/menus/thesaurus.rb +13 -0
  224. data/menus/to.rb +24 -0
  225. data/menus/twitter.rb +57 -0
  226. data/menus/wikipedia.rb +34 -0
  227. data/menus/words.rb +11 -0
  228. data/spec/code_tree_spec.rb +59 -0
  229. data/spec/diff_log_spec.rb +40 -0
  230. data/spec/file_tree_spec.rb +102 -0
  231. data/spec/keys_spec.rb +24 -0
  232. data/spec/line_spec.rb +68 -0
  233. data/spec/menu_spec.rb +50 -0
  234. data/spec/ol_spec.rb +98 -0
  235. data/spec/remote_spec.rb +43 -0
  236. data/spec/search_spec.rb +162 -0
  237. data/spec/text_util_spec.rb +119 -0
  238. data/spec/tree_cursor_spec.rb +91 -0
  239. data/spec/tree_spec.rb +955 -0
  240. data/tests/console_test.rb +11 -0
  241. data/tests/couch_db_test.rb +12 -0
  242. data/tests/diff_log_test.rb +43 -0
  243. data/tests/el_mixin.rb +16 -0
  244. data/tests/git_test.rb +95 -0
  245. data/tests/keys_test.rb +19 -0
  246. data/tests/line_test.rb +38 -0
  247. data/tests/merb_test.rb +11 -0
  248. data/tests/redmine_test.rb +50 -0
  249. data/tests/remote_test.rb +31 -0
  250. data/tests/rest_tree_test.rb +70 -0
  251. data/xiki.gemspec +37 -0
  252. metadata +332 -0
@@ -0,0 +1,860 @@
1
+ require 'block'
2
+ require 'stringio'
3
+ gem 'ruby2ruby'
4
+ require 'ruby2ruby'
5
+ gem 'ParseTree'
6
+ require 'parse_tree'
7
+ require 'parse_tree_extensions' # required for .to_ruby
8
+ class Code
9
+
10
+ def self.menu
11
+ %`
12
+ > Eval code
13
+ | Get return value and stdout
14
+ |
15
+ p Code.eval("puts 'printed'; 1 + 2")
16
+ `
17
+ end
18
+
19
+ def self.location_from_proc id
20
+ path = id.to_s
21
+ path =~ /@(.+):([0-9]+)/
22
+ file, line = $1, $2
23
+ [file, line]
24
+ end
25
+
26
+ def self.bounds_of_thing left=nil, right=nil
27
+
28
+ return [left, right] if left.is_a?(Fixnum)
29
+
30
+ return [Line.left, Line.right+1] if left == :line
31
+
32
+ n = Keys.prefix_n :clear=>true # Check for numeric prefix
33
+
34
+ return View.paragraph(:bounds=>1) if n == 0
35
+ return [Line.left, Line.left(n+1)] if n # If prefix, move down
36
+
37
+ return View.range if left.is_a?(Hash) && left[:default] == :region
38
+
39
+ [Line.left, Line.right] # Do line by default
40
+ end
41
+
42
+ def self.to_comment
43
+ $el.comment_search_forward View.bottom
44
+ end
45
+
46
+ def self.comment left=nil, right=nil
47
+
48
+ prefix = Keys.prefix
49
+
50
+ if prefix == 0 # If 0 prefix, comment paragraph
51
+ left, right = View.paragraph(:bounds => true)
52
+ else
53
+
54
+ if prefix == 2
55
+ a_commented = Line =~ /^ *(#|\/\/)/
56
+ b_commented = Line.value(2) =~ /^ *(#|\/\/)/
57
+ if !!a_commented ^ !!b_commented
58
+ Keys.clear_prefix
59
+ orig = Location.new
60
+ Code.comment Line.left(1), Line.left(2) # Toggle commenting of this line
61
+ Code.comment Line.left(2), Line.left(3) # Toggle commenting of next line
62
+ orig.go
63
+ return
64
+ end
65
+ end
66
+
67
+ Line.to_left
68
+ left ||= {:default=>:region}
69
+ left, right = Code.bounds_of_thing(left, right)
70
+ left, right = right, left if View.cursor == right # In case cursor is at right side
71
+ end
72
+
73
+ View.to left
74
+ View.set_mark right
75
+
76
+ $el.comment_or_uncomment_region View.range_left, View.range_right
77
+ Code.indent View.range_left, View.range_right
78
+ end
79
+
80
+ # Evaluates file, paragraph, or next x lines using el4r
81
+ def self.run options={}
82
+ prefix = Keys.prefix
83
+
84
+ if prefix == :uu
85
+ path = Tree.construct_path
86
+
87
+ load path
88
+ return View.flash "- loaded!"
89
+ end
90
+
91
+ if options[:left]
92
+ left, right = options[:left], options[:right]
93
+ txt = View.txt left, right
94
+ elsif prefix.is_a?(Fixnum) && 0 <= prefix && prefix <= 7
95
+ txt, left, right = View.txt_per_prefix nil, :blink=>1, :remove_heading=>1
96
+ else
97
+ case prefix
98
+ when :u # Load file in emacsruby
99
+ return self.load_this_file
100
+
101
+ # These were superceded by .txt_per_prefix apparently
102
+
103
+ when 8 # Put into file and run in console
104
+ File.open("/tmp/tmp.rb", "w") { |f| f << Notes.get_block("^>").text }
105
+ return Console.run "ruby -I. /tmp/tmp.rb", :dir=>View.dir
106
+ when 9 # Pass whole file as ruby
107
+ return Console.run("ruby #{View.file_name}", :buffer => "*console ruby")
108
+ else # Move this into ruby - block.rb?
109
+ ignore, left, right = View.block_positions "^>"
110
+ end
111
+
112
+ txt = View.txt(:left=>left, :right=>right).to_s
113
+ Effects.blink :left => left, :right => right
114
+ end
115
+
116
+ txt.sub! /\A( *)@ /, "\\1" # Remove @ if at beginning
117
+ txt.gsub! /^ *\| ?/, '' if txt =~ /\A *\|/ # Remove quoted lines if it's quoted
118
+
119
+ # If C--, define the launcher
120
+ if prefix == :-
121
+ if txt =~ /\A\s*class (\w+)/
122
+ clazz = $1
123
+ Launcher.add TextUtil.snake_case(clazz)
124
+ end
125
+ end
126
+
127
+ orig = Location.new
128
+ $el.goto_char right
129
+ after_code = Location.new # Remember right of code
130
+ orig.go
131
+
132
+ # Eval the code
133
+ returned, out, exception = self.eval txt
134
+ begin
135
+ if returned.any?
136
+ returned = returned.to_s[0..49]
137
+ returned << "..." if returned.length == 50
138
+ Message << returned
139
+ end
140
+ rescue
141
+ end
142
+ ended_up = Location.new
143
+
144
+ # Insert output
145
+ after_code.go
146
+
147
+ if prefix
148
+ View.insert(out.gsub /^/, ' ') unless out.blank?
149
+ else
150
+ View.insert(">>\n#{out}") unless out.blank?
151
+ end
152
+
153
+ if exception
154
+ backtrace = exception.backtrace[0..8].join("\n").gsub(/^/, ' ') + "\n"
155
+ View.insert "- error: #{exception.message}\n- backtrace:\n#{backtrace}".gsub(/^/, ' ')
156
+ end
157
+
158
+ orig.go # Move cursor back to where we started
159
+ ended_up.go # Go to where we ended up
160
+ end
161
+
162
+ def self.run_in_rails_console
163
+ left, after_header, right = View.block_positions "^>"
164
+ block = $el.buffer_substring after_header, right
165
+
166
+ View.to_after_bar if View.in_bar?
167
+
168
+ View.to_buffer "*rails console"
169
+ $el.erase_buffer
170
+ View.to_bottom
171
+
172
+ # if elvar.current_prefix_arg
173
+ # insert "reload!"
174
+ # command_execute "\C-m"
175
+ # end
176
+
177
+ $el.insert block
178
+ $el.command_execute "\C-m"
179
+
180
+ $el.beginning_of_buffer
181
+
182
+ end
183
+
184
+ def self.show_el4r_error
185
+ View.open $el.elvar.el4r_log_path
186
+ $el.revert_buffer(true, true, true)
187
+ View.wrap
188
+ View.to_end
189
+ $el.re_search_backward "^ from "
190
+ $el.re_search_backward "^[A-Z]"
191
+ $el.recenter 0
192
+ Color.colorize :r
193
+ end
194
+
195
+ def self.enter_ruby_log
196
+ txt = Clipboard.get("0")
197
+ $el.insert "Ol << \"#{txt}: \#{#{txt}}\""
198
+ end
199
+
200
+ def self.indent left=nil, right=nil
201
+ left, right = View.range if left.nil?
202
+ $el.indent_region(left, right)
203
+ end
204
+
205
+ # Evaluates a string, and returns the output and the stdout string generated
206
+ def self.eval code
207
+ return ['- Warning: nil passed to Code.eval!', nil, nil] if code.nil?
208
+ # Capture stdout output (saving old stream)
209
+ orig_stdout = $stdout; $stdout = StringIO.new
210
+ stdout = nil
211
+ exception = nil
212
+ begin # Run code
213
+ # Good place to debug
214
+ returned = $el.instance_eval(code, __FILE__, __LINE__)
215
+ rescue Exception => e
216
+ exception = e
217
+ end
218
+ stdout = $stdout.string; $stdout = orig_stdout # Restore stdout output
219
+ [returned, stdout, exception]
220
+ end
221
+
222
+ def self.do_as_align
223
+ $el.align_regexp
224
+ end
225
+
226
+ def self.open_related_rspec
227
+
228
+ # If in xiki project...
229
+
230
+ if View.file =~ /\/xiki\//
231
+ if View.file =~ /\/spec\// # If in spec, open corresponding file
232
+ View.open View.file.sub('/spec/', '/').sub(/_spec\.rb/, '.rb')
233
+ else # Otherwise, open file corresponding spec
234
+
235
+ method = Code.grab_containing_method :name=>1
236
+ path = View.file.sub(/(.+)\/(.+)/, "\\1/spec/\\2").sub(/\.rb/, '_spec.rb')
237
+ View.open path
238
+
239
+ View.recenter_under "^ *describe .+##{method}[^_a-zA-Z0-9]"
240
+ end
241
+
242
+ return
243
+ end
244
+
245
+ # If normal specs...
246
+
247
+ if View.file =~ /\/(app|spec)\//
248
+ if View.file =~ /\/app\// # If in file, open corresponding spec
249
+ unless Keys.prefix_u # Unless C-u, store method
250
+ orig = View.cursor
251
+ Move.to_end
252
+ Search.backward "^ +def "
253
+ method = Line.value[/^ +def (self\.)?(\w+)/, 2] # Save method name
254
+ View.cursor = orig
255
+ end
256
+
257
+ View.open View.file.sub('/app/', '/spec/unit/').sub(/\.rb/, '_spec.rb')
258
+
259
+ if method # Jump to method if they were on def... line
260
+ Keys.clear_prefix
261
+ View.to_highest
262
+ Search.forward "^ *describe .+##{method}[^_a-zA-Z0-9]", :beginning=>true
263
+ Line.to_beginning
264
+ View.recenter_top
265
+ end
266
+
267
+ else # Otherwise, open corresponding file
268
+ unless Keys.prefix_u # unless C-u, store method
269
+ orig = View.cursor
270
+ Move.to_end
271
+ Search.backward "^ *describe "
272
+ method = Line.value[/^ *describe .+#(\w+)/, 1] # Save method name
273
+ View.cursor = orig
274
+ end
275
+
276
+ View.open View.file.sub('/spec/unit/', '/app/').sub(/\_spec.rb/, '.rb')
277
+ View.open View.file.sub('/spec/', '/app/').sub(/\_spec.rb/, '.rb')
278
+
279
+ if method # Jump to method if they were on def... line
280
+ Keys.clear_prefix
281
+ View.to_highest
282
+ Search.forward "^ *def \\(self\\.\\)?#{method}[^_a-zA-Z0-9]", :beginning=>true
283
+ Line.to_beginning
284
+ View.recenter_top
285
+ end
286
+
287
+ end
288
+ return
289
+ end
290
+
291
+
292
+ View.beep
293
+ View.message "Don't recognize this file."
294
+ end
295
+
296
+ def self.do_as_rspec options={}
297
+ xiki = View.dir =~ /\/xiki/ # Identify if xiki
298
+ args = []
299
+ extra = "DS_SUPPRESS=true;"
300
+ prefix = Keys.prefix
301
+
302
+ return Specs.run_spec_in_place if prefix.nil?
303
+
304
+ if prefix == :u
305
+ args << "spec/unit"
306
+
307
+ if View.mode == :shell_mode # If already in shell, don't change dir
308
+ dir = nil
309
+ else
310
+ begin
311
+ dir, spec = View.file.match(/(.+)\/(spec\/.+)/)[1,2]
312
+ rescue
313
+ dir, spec = View.file.match(/(.+)\/(app\/.+)/)[1,2]
314
+ end
315
+ end
316
+
317
+ # Prefix must be something - 9, I guess, by convention??
318
+
319
+ elsif View.file !~ /_spec\.rb$/ # If not in an rspec file, delegate to: do_related_rspec
320
+ orig = Location.new
321
+ self.do_related_rspec
322
+ orig.go
323
+ return
324
+ else
325
+
326
+ if options[:line] # If specific line, just use it
327
+ args << '-l'
328
+ args << options[:line]
329
+ else # Otherwise, figure out what to run
330
+ orig = Location.new
331
+ orig_index = View.index
332
+
333
+ if prefix == 1 # If C-1, only run this test
334
+ else
335
+ before_search = Location.new
336
+ Line.next
337
+
338
+ # Find first preceding "it " or "describe "
339
+ it = Search.backward "^ *it ", :dont_move=>true
340
+ describe = Search.backward "^ *describe\\>", :dont_move=>true
341
+
342
+ if it.nil? && describe.nil?
343
+ View.beep
344
+ before_search.go
345
+ return View.message "Couldn't find it... or describe... block"
346
+ end
347
+
348
+ it ||= 0; describe ||= 0
349
+
350
+ if it > describe # If it, pass rspec -e "should...
351
+ extra = "DS_SUPPRESS=false; "
352
+ View.cursor = it
353
+ test = Line.value[/"(.+)"/, 1]
354
+ args << '-e'
355
+ args << "\"#{test}\""
356
+ else # If describe, pass rspec line number
357
+ View.cursor = describe
358
+ args << '-l'
359
+ args << View.line_number
360
+ end
361
+ before_search.go
362
+ end
363
+ end
364
+
365
+ # Chop off up until before /spec/
366
+ dir, spec = View.file.match(/(.+)\/(spec\/.+)/)[1,2]
367
+ args.unshift spec
368
+ end
369
+
370
+ buffer = "*console for rspec - #{dir}"
371
+ # If spec buffer open, just switch to it
372
+ if View.buffer_open? buffer
373
+ View.to_buffer buffer
374
+ else # Otherwise open it and run console
375
+ xiki ?
376
+ Console.run("", :dir=>dir, :buffer=>buffer) :
377
+ Console.run("bundle exec merb -i -e test", :dir=>dir, :buffer=>buffer)
378
+ # Console.run("merb -i", :dir=>dir, :buffer=>buffer)
379
+ # Console.run "merb -i -e test", :dir=>dir, :buffer=>buffer
380
+ end
381
+ View.clear
382
+
383
+ View.wrap(:on) if prefix == :u
384
+
385
+ # args << '-D' # Show diffs
386
+
387
+ if xiki
388
+ command = "#{extra}spec #{args.join(' ')}"
389
+ else
390
+ args = args.map{|o| o =~ /^"/ ? o : "\"#{o}\"" }.join(",\n") # Only add quotes if not already there
391
+ command = "Spec::Runner::CommandLine.run(Spec::Runner::OptionParser.parse([#{args}], $stderr, $stdout))"
392
+ # Rails version (commented out - it's currently hard-coded to use merb)
393
+ # command = "#{extra}p :reload; reload!; #{command}"
394
+ end
395
+ View.insert command
396
+ Console.enter
397
+ View.to 1
398
+
399
+ orig.go unless orig.nil? || View.index == orig_index # Go back unless in same view
400
+ end
401
+
402
+ def self.do_related_rspec
403
+ # Find method name
404
+ orig = View.cursor
405
+ Line.next
406
+ Search.backward "^ +def "
407
+ meth = Line.value[/def ([\w.!]+)/, 1].sub /^self\./, ''
408
+
409
+ View.cursor = orig
410
+
411
+ # Go to relevant test
412
+ Code.open_related_rspec
413
+
414
+ # Find test for method:
415
+ View.to_highest
416
+ Search.forward "^ *describe .+, \"##{meth}\" do"
417
+ Move.to_axis
418
+ View.recenter_top
419
+ Code.do_as_rspec :line=>View.line_number
420
+
421
+ # Run test
422
+ end
423
+
424
+ def self.load_this_file
425
+ Effects.blink :what=>:all
426
+ begin
427
+ load View.file
428
+ rescue Exception=>e
429
+ Tree.<< "- Error:\n#{e.message.gsub /^/, ' '}!", :no_slash=>1
430
+ end
431
+ end
432
+
433
+ def self.do_code_align
434
+ left, right = $el.bounds_of_thing_at_point(:paragraph).to_a
435
+ align_regexp(left, right, "\\( *\\)"+Keys.input(:prompt => "align to regex: "), 1, 3, true)
436
+ end
437
+
438
+ #
439
+ # Indent selected lines.
440
+ #
441
+ # - do+indent # Indent to the right (by 2 spaces)
442
+ # - up+do+indent # Indent to the left (by 2 spaces)
443
+ # - 3+do+indent # Make indent be 6 spaces from the left (3*2)
444
+ #
445
+ def self.indent_to
446
+
447
+ prefix = Keys.prefix
448
+ return Code.indent if prefix == :- # Just indent to where it should go
449
+
450
+ txt = View.selection
451
+ old_indent = txt[/^( *)[^ \n]/, 1]
452
+
453
+ new_indent =
454
+ if ! prefix
455
+ old_indent.length + 2
456
+ elsif prefix == :u
457
+ old_indent.length - 2
458
+ elsif prefix.is_a?(Fixnum)
459
+ prefix * 2
460
+ else
461
+ raise ".blink Don't know how to indent by '#{prefix}'"
462
+ end
463
+
464
+ return if new_indent < 0
465
+
466
+ orig = Location.new
467
+ View.delete
468
+
469
+ # Grab indent if 1st line that has text
470
+ txt.gsub!(/^\s+/) { |t| t.gsub("\t", ' ') } # Untab indent
471
+ txt.gsub! /^#{old_indent}/, ' ' * new_indent
472
+
473
+ txt.gsub!(/^ +$/, '') # Kill trailing spaces on lines with just spaces
474
+
475
+ View.insert txt
476
+
477
+ if orig.line != Line.number # If we're at the end
478
+ View.set_mark
479
+ orig.go
480
+ end
481
+
482
+ end
483
+
484
+ def self.enter_as_backslash
485
+ txt = Clipboard.get("0")
486
+ txt.strip!
487
+ txt.gsub!(/$/, "\\") # Add \'s
488
+ txt.gsub!(/\\\z/, '') # Remove last \
489
+ $el.insert txt
490
+ end
491
+
492
+ def self.enter_as_debug
493
+
494
+ orig = View.range[0]
495
+ txt = View.selection :delete=>true
496
+ count = 0
497
+ txt.gsub!(/^.+/) { |m|
498
+ if m =~ /^\s+(end|else|elsif|\})/
499
+ m
500
+ else
501
+ count += 1;
502
+ (count & 1 == 0) ? " ol #{count}\n#{m}" : m
503
+ end
504
+ }
505
+
506
+ View.insert txt
507
+ View.to orig
508
+ end
509
+
510
+ def self.kill_duplicates
511
+ txt = View.selection :delete=>true
512
+ l = txt.split("\n")
513
+ orig = Location.new
514
+ View.insert l.uniq.join("\n") + "\n"
515
+ View.set_mark
516
+ orig.go
517
+ end
518
+
519
+ def self.randomize_lines txt=nil
520
+ txt ||= View.selection :delete=>true
521
+ l = txt.split("\n")
522
+ orig = Location.new
523
+ View.insert l.sort_by{ rand }.sort_by{ rand }.join("\n") + "\n"
524
+ View.set_mark
525
+ orig.go
526
+ end
527
+
528
+ def self.do_next_paragraph
529
+ orig = Location.new
530
+ line = Line.value 1, :include_linebreak=>true, :delete=>true # Get line
531
+ Move.backward
532
+ Search.forward "\n\n+"
533
+ View.insert line
534
+
535
+ orig.go
536
+ end
537
+
538
+ def self.enter_log_clipboard
539
+ clip = Clipboard[0]
540
+ View.insert "Ol << \"#{clip}: \#{#{clip}}\""
541
+ return
542
+ end
543
+
544
+ def self.enter_log_stack
545
+ return View.insert "p_stack()" if View.extension == "js"
546
+ View.insert "Ol.stack"
547
+ end
548
+
549
+ def self.enter_log_console
550
+ View.insert "console.log();"
551
+ Move.backward 2
552
+ end
553
+
554
+ def self.open_log_view options={}
555
+ prefix = Keys.prefix :clear=>true
556
+ prefix = nil if options[:called_by_launch]
557
+ orig = View.current if prefix == :u
558
+
559
+ file = Ol.file_path
560
+
561
+ buffer = "*ol"
562
+
563
+ # If already open, just go to it
564
+ if View.buffer_visible?(buffer)
565
+ View.to_buffer(buffer)
566
+ return if self.clear_and_go_back orig
567
+ end
568
+
569
+ # If 2 or more windows open
570
+ if View.list.size == 2
571
+ View.to_nth(1) # Go to 2rd
572
+ elsif View.list.size >= 3
573
+ View.to_nth(2)
574
+ unless View.left_edge == 0 # If 3nd not at left, go to 2nd
575
+ View.to_nth(1)
576
+ unless View.left_edge == 0 # If not at left, go to first
577
+ View.to_nth(0)
578
+ end
579
+ View.create
580
+ end
581
+ end
582
+
583
+ # If buffer open, just switch to it
584
+ if View.buffer_open? buffer
585
+ View.to_buffer buffer
586
+ return if self.clear_and_go_back orig
587
+ return
588
+ end
589
+
590
+ return if file.nil? or file.empty?
591
+
592
+ # Create file if not there
593
+ `touch #{file}` unless File.exists?(file)
594
+ lines = "#{file}.lines"
595
+ `touch #{lines}` unless File.exists?(lines)
596
+
597
+ Console.run "tail #{prefix == :- ? '-n 100' : ''} -f #{file}", :buffer=>buffer, :dir=>'/tmp', :dont_leave_bar=>true
598
+ Notes.mode
599
+
600
+ return if self.clear_and_go_back orig
601
+ end
602
+
603
+ def self.enter_log_line
604
+
605
+ return Firefox.enter_log_javascript_line if View.extension == "js"
606
+
607
+ $el.open_line(1) unless Line.blank?
608
+
609
+ # Javascript
610
+ if Tree.construct_path(:all=>1, :slashes=>1) =~ /<script/
611
+ View << "console.log('!');"
612
+ return Move.backward 4
613
+ end
614
+
615
+ if Keys.prefix_u?
616
+ View.insert 'Ol << "!"'
617
+ return Move.backward 2
618
+ end
619
+
620
+ View.insert "Ol.line"
621
+ Line.to_left
622
+ end
623
+
624
+ def self.enter_log_output
625
+ orig = Location.new
626
+ View.layout_output
627
+
628
+ output = Line.value[/: (.+)/, 1]
629
+ orig.go
630
+
631
+ return View.flash("- Not found!") if output.nil?
632
+
633
+ Move.to_end
634
+ View.insert_line
635
+ View << "# #{output}"
636
+ Line.to_beginning
637
+ end
638
+
639
+ def self.enter_log_time
640
+ $el.open_line(1) unless Line.blank?
641
+ View.insert("Ol.time")
642
+ Line.to_left
643
+ end
644
+
645
+ def self.to_ruby o
646
+ o.to_ruby
647
+ end
648
+
649
+ def self.isearch_just_should
650
+ Search.stop
651
+ term = Search.match
652
+ View.delete(Search.left, Search.right)
653
+ View.insert term.sub(/\.(.+)/, ".should_receive(:\\1)")
654
+ end
655
+
656
+ def self.clear_and_go_back location
657
+ if location # Go back to starting point
658
+ View.clear
659
+
660
+ View.clear "*ol"
661
+ View.to_window location
662
+ return true # Indicate to exit method
663
+ end
664
+ return false # Don't exit
665
+ end
666
+
667
+ def self.do_list_ancestors
668
+ prefix = Keys.prefix :clear=>1
669
+
670
+ result = Tree.ancestors_indented
671
+
672
+ result = result.strip.gsub('%', '%%')
673
+
674
+ # If U, save in clipboard as quote, ready to be pasted into a tree
675
+ # Clipboard[0] = result if Keys.prefix_u
676
+
677
+ if prefix == :- # Actually insert it inline
678
+ Line.next
679
+ View << "#{result}\n"
680
+ Line.previous
681
+ return
682
+ end
683
+
684
+ if prefix == :u # Just recenter to method
685
+ View.recenter_under "^\\( *def \\| *it \\|^>\\)", :relative=>1
686
+ elsif prefix == :uu
687
+ result = "Cursor: #{View.cursor}"
688
+ end
689
+
690
+ View.message result
691
+ end
692
+
693
+ def self.add_space
694
+
695
+ left, right = View.range
696
+ right = Line.right if left == right
697
+
698
+ scroll = View.scroll_position
699
+
700
+ View.cursor = right
701
+ View << "\n\n\n\n\n\n"
702
+ View.cursor = left
703
+ View << "\n\n\n\n\n\n"
704
+
705
+ View.scroll_position = scroll
706
+
707
+ end
708
+
709
+ def self.open_related_file
710
+ file = View.file
711
+
712
+ return View.open(file.sub /\.menu$/, '.rb') if file =~ /\/menus\/\w+\.menu$/
713
+ return View.open(file.sub /\.rb$/, '.menu') if file =~ /\/menus\/\w+\.rb$/
714
+
715
+ View.flash "No matching file known."
716
+
717
+ end
718
+
719
+
720
+ # Can be used by menus with dsl's that need to parse strings like:
721
+ # "bb(hi(xx)) aa(11)"
722
+ #
723
+ # Usage:
724
+ # h = {}
725
+ # Code.parse_functions "a(hi(xx)) b(11)c(a)", h
726
+ # Code.parse_functions "z(1)", h
727
+ # p h
728
+ # => {0=>["a(hi(xx))", "z(1)"], 11=>["b(11)"], 17=>["c(a)"]}
729
+ def self.parse_functions txt, initial_hash={}
730
+ s = StringScanner.new(txt)
731
+
732
+ i = 0
733
+
734
+ # Loop until none left
735
+ while(! s.eos?)
736
+ item = ""
737
+
738
+ i += s.scan(/ */).length
739
+ break if s.eos?
740
+
741
+ item << s.scan(/\w+/)
742
+
743
+ chunk = s.scan(/[(]/)
744
+ raise "There was supposed to be a paren at index #{i + item.length} of #{txt.inspect}" if chunk != "("
745
+ item << chunk
746
+ paren_depth = 1
747
+
748
+ # Scan until found closing parens
749
+ while(chunk && paren_depth > 0)
750
+ chunk = s.scan(/.*?[()]/)
751
+ item << chunk
752
+ paren_depth += item[/\($/] ? 1 : -1 # Adjust depth based on char at end
753
+ end
754
+
755
+ initial_hash[i] ||= []
756
+ initial_hash[i] << item
757
+
758
+ i += item.length
759
+ end
760
+ initial_hash
761
+ end
762
+
763
+ def self.enter_whitespace
764
+
765
+ prefix = Keys.prefix :clear=>1
766
+
767
+ if prefix == :u
768
+ column = View.column
769
+ Move.to_axis; View << "\n"
770
+ Move.to_end; View >> "\n"
771
+ View.column = column
772
+ return
773
+ end
774
+
775
+ $el.open_line(prefix || 1)
776
+
777
+ end
778
+
779
+ # Searches upward for "def..." and returns the line
780
+ def self.grab_containing_method options={}
781
+ orig = Location.new
782
+ Search.backward "^ def "
783
+ txt = Line.value
784
+ orig.go
785
+
786
+ return txt[/def (self\.)?(\w+)/, 2] if options[:name]
787
+
788
+ txt
789
+ end
790
+
791
+ # Convenience for entering "# " to start a comment
792
+ def self.enter_insert_comment
793
+ if Line.blank?
794
+ View << "# "
795
+ $el.ruby_indent_line
796
+ else
797
+ Move.to_end
798
+ View << " # "
799
+ end
800
+
801
+ ControlLock.disable # insert date string (and time if C-u)
802
+ end
803
+
804
+ def self.launch_dot_at_end line
805
+ prefix = Keys.prefix :clear=>1
806
+
807
+ # If just Foo., show methods
808
+
809
+ if line =~ /\A\w+\.\z/
810
+ txt = Code.eval("#{line}meths")[0].map{|o| "- #{o}" }.join("\n")
811
+ return Tree.<< txt, :no_slash=>1
812
+ end
813
+
814
+ if prefix == "open" # If as+open, just navigate there
815
+ return Search.open_file_and_method line.sub("./.", '.')
816
+ end
817
+
818
+ # It's foo./.bar/, so go to parent, collapse, and add this at end
819
+
820
+ last = line.split('/').last
821
+ Tree.to_parent
822
+ CodeTree.kill_rest
823
+ Line.sub! /\.$/, "#{last}"
824
+ Move.to_end
825
+
826
+ # If Foo. ... .bar, merge it back to parent (make Foo.bar), then launch
827
+
828
+ end
829
+
830
+ def self.suggest_creating_method file, method
831
+
832
+ View.open "method doesn't exist", :txt=>"
833
+ > Method doesn't exist. Create it?
834
+
835
+ #{file}
836
+ |+
837
+ |+ def self.#{method}
838
+ |+
839
+ |+ end
840
+ | end
841
+ ".unindent
842
+
843
+ View.line = 4
844
+ View.column = 2
845
+
846
+ end
847
+
848
+ #
849
+ # Grabs /foo/bar.rb:123 pattern from line, and jumps to file / line.
850
+ #
851
+ def self.open_as_file
852
+ return if Line.value !~ /(\/.+?):(\d+)/
853
+
854
+ file, line = $1, $2
855
+ View.open file
856
+ View.line = line
857
+ end
858
+
859
+ end
860
+