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,476 @@
1
+ require 'line'
2
+ require 'ol'
3
+
4
+ class CodeTree
5
+
6
+ def self.menus; @menus; end
7
+
8
+ def self.add_menu item
9
+ @menus ||= []
10
+ @menus << item unless @menus.member? item
11
+ end
12
+
13
+ # Mapped to C-.
14
+ def self.launch options={}
15
+ line = Line.without_indent
16
+
17
+ return Search.open_file_and_method line if Keys.open? # If as+open, just navigato to it!
18
+
19
+ FileTree.extra_line_if_end_of_file
20
+ Tree.plus_to_minus_maybe
21
+ orig = Location.new
22
+ Line.to_left
23
+ path = options[:path] || Tree.construct_path(:list=>true)
24
+ path.each do |l|
25
+ # if '- .xx:/", get rid of trailing slash
26
+ l.sub!(/^([+-] .*\..+)\/$/, "\\1")
27
+ end
28
+ # Determine code to eval
29
+ code = self.determine_code_from_path path
30
+ orig.go
31
+
32
+ self.run code, options
33
+ end
34
+
35
+ def self.returned_to_s returned
36
+
37
+ if returned.is_a? String # Join and bulletize
38
+ returned
39
+ elsif returned.is_a? Array # Join and bulletize
40
+ returned.map{|l| "#{l =~ /\/$/ ? '+' : '-'} #{l}\n"}.join('')
41
+ elsif returned.is_a? Hash
42
+ (returned.map{|k, v| v =~ /\/$/ ? "+ #{k}: #{v}" : "- #{k}: #{v}"}.join("\n")) + "\n"
43
+ else
44
+ returned.to_s.strip
45
+ end
46
+ end
47
+
48
+ def self.draw_exception exception, code=nil
49
+ message = exception.message
50
+
51
+ # TODO: pay attention to this option?
52
+ # Ol << "options[:suggest_args]: #{options[:suggest_args].inspect}"
53
+
54
+ # TODO
55
+ # For now, don't do it!
56
+ # - How to not show "arg1" etc
57
+ # - when ArgumentError is code deeper than the immediate one
58
+ # if exception.is_a? ArgumentError
59
+ # count, required = message.match(/\((\d+) for (\d+)\)/)[1..2]
60
+ # if count < required # We can't add sample args if too many were supplied
61
+ # return (count.to_i+1..required.to_i).to_a.map{|o| "arg#{o}"}.join('/')+"/"
62
+ # end
63
+ # end
64
+
65
+
66
+ if exception.is_a? RuntimeError
67
+ # If it was in the format of tree output, just show it
68
+
69
+ # Some messages start with "path:line:...: " at beginning again
70
+
71
+ message.sub!(/.+?: /, '') if message =~ /in `/
72
+
73
+ return message if message =~ /\A[>|+-] / # /^- /
74
+ return View.prompt($1) if(message =~ /\A\.prompt (.+)/)
75
+ return View.flash($1) if(message =~ /\A\.flash (.+)/)
76
+ end
77
+
78
+ backtrace = exception.backtrace[0..8].join("\n").gsub(/^/, ' ') + "\n"
79
+
80
+ # If path in message, move it to the stack trace
81
+ if message =~ /(.+\d:in `.+'): (.+)/m
82
+ path, message = $1, $2
83
+ backtrace = " #{path}\n#{backtrace}"
84
+ end
85
+
86
+ message = message =~ /\n/ ?
87
+ "\n"+message.strip.gsub(/^/, " | ").gsub(/^( +\|) ([+-])/, "\\1\\2") :
88
+ " #{message}"
89
+
90
+ txt = ""
91
+ txt << "- tried to run: #{code}\n" if code
92
+ txt << "- error:#{message}\n- backtrace:\n#{backtrace}"
93
+ txt
94
+ end
95
+
96
+ def self.run code, options={}
97
+ b = View.buffer
98
+
99
+ orig = Location.new
100
+ orig_left = $el.point
101
+
102
+ returned, stdout, e = Code.eval(code) # Eval code
103
+ # If no stdout (and something was returned), print return value
104
+ if ! stdout.nonempty? and ! returned.nil?
105
+ stdout = self.returned_to_s returned
106
+ else
107
+ message(returned.to_s) if returned and (!returned.is_a?(String) or returned.size < 500)
108
+ end
109
+
110
+ stdout = self.draw_exception(e, code) if e
111
+
112
+ buffer_changed = b != View.buffer # Remember whether we left the buffer
113
+ # Insert output if there was any
114
+ if stdout.nonempty?
115
+ # Pull out flags
116
+ if stdout =~ /^:code_tree_option_tree_search\n/
117
+ options[:tree_search] = true
118
+ stdout.sub! /.+\n/, '' # Remove option
119
+ elsif stdout =~ /^:quote_search_option\n/
120
+ options[:quote_search] = true
121
+ stdout.sub! /.+\n/, '' # Remove option
122
+ elsif stdout =~ /^:code_tree_option_no_search\n/
123
+ options[:no_search] = true
124
+ stdout.sub! /.+\n/, '' # Remove option
125
+ end
126
+ ended_up = Location.new
127
+
128
+ # Go back to where we were before running code
129
+ orig.go
130
+ indent = Line.indent
131
+ Line.to_left
132
+ Line.next
133
+ left = $el.point
134
+
135
+ # Move what they printed over to left margin initally, in case they haven't
136
+ stdout = TextUtil.unindent(stdout)
137
+ stdout.sub!(/\n\n\z/, "\n") # Remove any double linebreaks at end
138
+
139
+ stdout.gsub!(/^/, "#{indent} ")
140
+
141
+ View << stdout # Insert output
142
+ right = $el.point
143
+
144
+ orig.go # Move cursor back
145
+ ended_up.go # End up where script took us
146
+
147
+ # These are deprecated - eventually pull them out
148
+ if options[:tree_search] # If they want to do a tree search
149
+ $el.goto_char left
150
+ FileTree.select_next_file
151
+ Tree.search(:left=>left, :right=>right, :recursive=>true)
152
+ return
153
+ end
154
+ if options[:quote_search] # If they want to do a tree search
155
+ $el.goto_char left
156
+ Search.forward "|"
157
+ Line.to_beginning
158
+ Tree.search(:left=>left, :right=>right, :recursive_quotes=>true)
159
+ return
160
+ end
161
+
162
+ # If script didn't move us (line or buffer), do incremental search
163
+ if !options[:no_search] && !buffer_changed && $el.point == orig_left
164
+ # TODO No search if there aren't more than 3 lines
165
+ $el.goto_char left
166
+
167
+ Line.to_words
168
+
169
+ # Determine how to search based on output!
170
+
171
+ Tree.search_appropriately left, right, stdout
172
+
173
+ elsif options[:no_search]
174
+ Line.to_beginning :down=>1
175
+ end
176
+
177
+ end
178
+ end
179
+
180
+ def self.menu
181
+ l = []
182
+ ObjectSpace.each_object(Class) do |c|
183
+ next unless c.respond_to?(:menu)
184
+ l << c.to_s
185
+ end
186
+ l.map! {|c| c.sub(/^#.+::/, '')}
187
+ (l + menus).sort.each do |c|
188
+ next if ["CodeTree"].member?(c)
189
+ puts "+ #{c}.menu/"
190
+ end
191
+ ""
192
+ end
193
+
194
+ def self.layout_menu
195
+ View.bar if Keys.prefix_u?
196
+
197
+ buffer = "*CodeTree CodeTree menu"
198
+ if View.buffer_open? buffer # If open, switch to it
199
+ View.to_buffer(buffer)
200
+ else # Else open it
201
+ Launcher.open("- CodeTree.menu/")
202
+ end
203
+ end
204
+
205
+ # Determine whether we should handle it
206
+ def self.handles? list=nil
207
+ list ||= Tree.construct_path(:list => true) # Use current line by default
208
+
209
+ code_tree_root = nil
210
+ index = list.size - 1
211
+
212
+ # If @..., don't bother with rest of path
213
+ list = [list[-1]] if list[-1][/^ *([+-] )?@/]
214
+
215
+ list.reverse.each do |l|
216
+
217
+ # If it has a char that wouldn't be in a file, must be code tree
218
+ #return index if l =~ /[\[\{=]/
219
+
220
+ # If last one was suspected as root, confirm we're not a dir (must be a file if parent is a dir)
221
+ if code_tree_root
222
+ if l =~ /\/$/ # Dir means it was a file that looked like code
223
+ # This means never interpret classes indented under foo/
224
+ code_tree_root = nil
225
+ else
226
+ return index + 1 # Must be legit, so return our index
227
+ end
228
+ end
229
+ # If function call, it might be the root
230
+ if l =~ /^[+-]? ?@?[A-Z][A-Za-z0-9]*\.[a-z_]/
231
+ code_tree_root = index
232
+ end
233
+ index -= 1
234
+ end
235
+ code_tree_root
236
+ end
237
+
238
+ # Rules for constructing code from path
239
+ # - examine path consisting of where C-. occurred and all its ancestors
240
+ # - root of tree is first ancestor with Class.method
241
+ # - invoke first ancestor method (using its params)
242
+ # - append all ancestor data nodes as params
243
+ # - include self if a data node
244
+ def self.determine_code_from_path path
245
+ data = []
246
+ clazz = metho = nil
247
+ metho_maybe = clazz_maybe = nil
248
+
249
+ i = -1
250
+
251
+ path.reverse.each do |l| # Climb up path
252
+ i += 1
253
+
254
+ l.sub! /^@/, '' # Remove delegate, so it's respected
255
+
256
+ metho_tmp = self.extract_method(l)
257
+ clazz_tmp = self.extract_class(l)
258
+ l.sub(/^(\s+)[+-] /, "\\1") # Remove bullets
259
+ is_root = i + 1 == path.size
260
+ code_node = false
261
+ if metho_tmp # If line has method
262
+ if clazz_tmp # If line has class
263
+ if is_root || self.definite_code_tree_root(l)
264
+ metho ||= metho_tmp
265
+ code_node = true
266
+ clazz ||= clazz_tmp
267
+ break if clazz
268
+ else # Use this if nothing else is found
269
+ metho_maybe ||= metho_tmp
270
+ clazz_maybe ||= clazz_tmp
271
+ end
272
+ else # Otherwise, it can be a method
273
+ metho ||= metho_tmp
274
+ code_node = true
275
+ end
276
+ end
277
+ if ! code_node # If not code node, must be data node
278
+ # Prepend to data list
279
+ data << self.paramify(l)
280
+ end
281
+ end
282
+
283
+ unless clazz # If no code found
284
+ return nil unless clazz_maybe
285
+ metho = metho_maybe
286
+ clazz = clazz_maybe
287
+ data = []
288
+ end
289
+
290
+ # If one line, return it literally
291
+ if i == 0
292
+ return Line.without_label(:line=>path[-1]).sub(/\/$/, '')
293
+ end
294
+
295
+ # Extract any params from after method
296
+ method_with_params, params = metho.match(/(\w+\??)(.*)/)[1..2]
297
+ params.sub!(/^\((.*)\)$/, "\\1") # Remove parens if they're there
298
+
299
+ # Surround with curly brackets if it's a hash, and no curly brackets already
300
+ # Assumes all params are in a hash, which may not be right
301
+ if params =~ /=>/ && params !~ /\}$/
302
+ params = " {#{params.strip}}"
303
+ end
304
+
305
+ # If last parameter was |..., make it be all the lines
306
+ if data.first =~ /^ *\|/
307
+ data.first.replace( self.escape(
308
+ Tree.siblings(:all=>true).map{|i| "#{i[/^ *\| ?(.*)/, 1]}\n"}.join('')
309
+ ))
310
+ end
311
+
312
+ # If any data nodes, pass as params
313
+ if ! data.empty?
314
+ data.reverse!
315
+ data.map! {|a| "\"#{a}\""}
316
+ params << ", " + data.join(", ")
317
+ end
318
+ # TODO Get rid of comma if there is one
319
+ params.sub!(/^, /, '')
320
+ "#{clazz}.#{method_with_params}(#{params})"
321
+ end
322
+
323
+ def self.extract_class l
324
+ l[/^([A-Z][A-Za-z0-9]*)\.[a-z_]/, 1]
325
+ end
326
+
327
+ def self.extract_method l
328
+ l = l.sub(/^[+-] [\w -]+?: /, '').sub(/^[+-] /, '') # Remove bullets
329
+ # Either class or bol
330
+ result = l[/^[A-Z][A-Za-z0-9]*\.([a-z_].*)/, 1] || # Class and method
331
+ l[/^\.([a-z].*)/, 1] # Method at beginning of line
332
+ result ? result.sub(/\/$/, '') : nil
333
+ end
334
+
335
+ def self.paramify l
336
+ l = Line.without_label(:line=>l)
337
+
338
+ l = self.escape(l)
339
+ if l =~ /^\|/ # If |..., escape single-quotes
340
+ # l.gsub!("'", "\\'")
341
+ else
342
+ l.gsub! ', ', '", "'
343
+ end
344
+
345
+ l
346
+ end
347
+
348
+ # Always escape backslashes, single-quotes, #'s
349
+ def self.escape l
350
+ l = l.gsub("\\", "\\\\\\\\")
351
+ l.gsub!("\"", "\\\\\"")
352
+ l.gsub!("#", "\\\\#")
353
+ l
354
+ end
355
+
356
+
357
+ def self.kill_siblings options={}
358
+ prefix = Keys.prefix :clear=>true
359
+
360
+ left1, right1, left2, right2 = Tree.sibling_bounds
361
+
362
+ # If number, adjust
363
+
364
+ if prefix.is_a?(Fixnum)
365
+ left2 = Line.left prefix + 1
366
+ elsif prefix == :u
367
+ right2 = left2
368
+ elsif prefix == :uu
369
+ right1 = left1
370
+ end
371
+
372
+ View.delete left2, right2
373
+ View.delete left1, right1
374
+ end
375
+
376
+ def self.do_kill_indented options={}
377
+ if Keys.up? || options[:cross_blank_lines]
378
+ left, right = Tree.sibling_bounds :cross_blank_lines=>1
379
+ else
380
+ left, ignore1, ignore2, right = Tree.sibling_bounds
381
+ end
382
+
383
+ View.cursor = left
384
+ $el.set_mark right
385
+ Effects.blink :left=>left, :right=>right # unless options[:dont_cross_blank_lines]
386
+
387
+ View.delete left, right
388
+
389
+ end
390
+
391
+ def self.as_indented
392
+ prefix = Keys.prefix :clear=>1
393
+
394
+ indent = Line.indent.length
395
+
396
+ # If at left margin or current line followed by child
397
+ if prefix != :u && (prefix == :- || indent == 0 || indent == Line.indent(Line.value(2)).length - 2)
398
+ orig = View.cursor
399
+ left = Line.left
400
+ Line.next
401
+ ignore, right = Tree.sibling_bounds :cross_blank_lines=>1
402
+ View.cursor = orig
403
+ elsif prefix == :u
404
+ left, ignore1, ignore2, right = Tree.sibling_bounds
405
+ else
406
+ left, right = Tree.sibling_bounds :cross_blank_lines=>1
407
+ end
408
+ View.cursor = left
409
+ $el.set_mark right
410
+ Effects.blink :left=>left, :right=>right
411
+
412
+ Clipboard.copy "0"
413
+
414
+ end
415
+
416
+ def self.kill_rest
417
+ prefix = Keys.prefix(:clear=>true)
418
+ column = View.column
419
+
420
+ right1 = Line.left
421
+ left2 = Line.left 2
422
+
423
+ Line.next if Search.backward("^$", :go_anyway=>true) # Go to beginning of paragraph
424
+ left1 = Line.left
425
+
426
+ Search.forward("^$", :go_anyway=>true) # Go to end of paragraph
427
+ right2 = Line.left
428
+
429
+ if prefix.is_a?(Fixnum)
430
+ View.cursor = left2
431
+ right2 = Line.left(prefix + 1)
432
+ end
433
+
434
+ View.delete left2, right2 # Always delete after
435
+ Line.previous
436
+
437
+ # Optionally delete before
438
+ View.delete(left1, right1) if prefix == :u
439
+ end
440
+
441
+ def self.tree_search_option
442
+ ":code_tree_option_tree_search\n"
443
+ end
444
+
445
+ def self.quote_search_option
446
+ ":quote_search_option\n"
447
+ end
448
+
449
+ def self.no_search_option
450
+ ":code_tree_option_no_search\n"
451
+ end
452
+
453
+ def self.definite_code_tree_root line
454
+ line =~ /^[\s+-]*[A-Z].+\..+[\/)]$/
455
+ end
456
+
457
+ def self.maybe_code_tree_root line
458
+ line =~ /^[\s+-]*[A-Z].+\.[a-z_]/
459
+ end
460
+
461
+ def self.definite_dir_tree_root line
462
+ line =~ /^[\s+-]*\//
463
+ end
464
+
465
+ # Turn list into bulleted string (adding + or - based on ending in slash)
466
+ def self.bulletize list
467
+ (list.map{|l| l =~ /\/$/ ? "+ #{l}" : "- #{l}"}.join("\n")) + "\n"
468
+ end
469
+
470
+ def self.remove_slashes *args
471
+ args.each do |arg|
472
+ arg.sub! /\/$/, '' if arg
473
+ end
474
+ end
475
+
476
+ end