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,57 @@
1
+ class Ruby
2
+ def self.menu
3
+ "
4
+ - .classes/
5
+ - .re_index_fast_ri/
6
+ - .docs/
7
+ > Ruby docs
8
+ @$ qri -h
9
+
10
+ > Eval code
11
+ | Evaluate the ruby code on adjascent lines, until a '> ...' heading.
12
+ @eval
13
+ puts('hi')
14
+ - @eval/
15
+ - @technologies/ruby/
16
+ - language docs/
17
+ > Listing and categories of gems
18
+ @ https://www.ruby-toolbox.com/
19
+ "
20
+ end
21
+
22
+ def self.classes clazz=nil, method=nil
23
+
24
+ # If no params, show list of classes
25
+
26
+ if clazz.nil?
27
+ result = []
28
+ ObjectSpace.each_object(Class) do |c|
29
+ name = c.to_s
30
+ next if name =~ /^#/
31
+ result << "- #{name}/\n"
32
+ end
33
+ return result.sort.join
34
+ end
35
+
36
+ # If just class, show methods
37
+
38
+ if method.nil?
39
+ result = ""
40
+ result << Kernel.const_get(clazz).instance_methods(false).sort.
41
+ collect {|i| "- #{i}/" }.join("\n")
42
+ result << Kernel.const_get(clazz).methods(false).sort.
43
+ collect {|i| "- ::#{i}/" }.join("\n")
44
+ return result
45
+ end
46
+
47
+ # If method passed, lookup method's doc
48
+
49
+ method = "##{method}" unless method =~ /^::/
50
+ command = "qri #{clazz}#{method}"
51
+ Console[command].gsub(/\C-[.+?m/, '').gsub(/^/, '| ').gsub(/^\| +$/, '|')
52
+ end
53
+
54
+ def self.re_index_fast_ri
55
+ Console.run "fastri-server -b"
56
+ end
57
+ end
@@ -0,0 +1,165 @@
1
+ gem 'net-ssh'
2
+ require 'net/ssh'
3
+
4
+ # Wraps around a local or remote irb or merb (and probably rails)
5
+ # console, passing commands to it and returning their stdout output.
6
+ class RubyConsole
7
+
8
+ @@output = ""
9
+ def self.output; @@output; end
10
+
11
+ @session = @channel = nil
12
+
13
+ CODE_SAMPLES = %q<
14
+ # Send something to a local irb console
15
+ RubyConsole.run("puts 'hey'")
16
+
17
+ # Send something to a merb console
18
+ RubyConsole.register(:foo, 'merb -m /projects/foo -i') # Do this only once
19
+ RubyConsole[:foo].run("y Account.first")
20
+ >
21
+
22
+ @@registered = {}
23
+
24
+ def initialize console_command='irb', server=nil
25
+ @console_command, @server = console_command, server
26
+ end
27
+
28
+ def connect
29
+ begin
30
+ timeout(25) do
31
+ open_channel # Connect
32
+ # TODO: try to indent this
33
+ send_it %Q[conf.echo = false
34
+ # Temporary hack for nuby 1.8.4
35
+ $out_bufr = defined?(StringIO) ? StringIO.new : ''
36
+
37
+ module Kernel
38
+ def puts *args
39
+ args.each { |a|
40
+ $out_bufr << (
41
+ (a.class == Array) ?
42
+ (a.join("\\n") + "\\n") :
43
+ "\#{a}\\n"
44
+ )
45
+ }
46
+ nil
47
+ end
48
+ def p *args
49
+ args.each { |a| $out_bufr << "\#{a.inspect}\n" }
50
+ nil
51
+ end
52
+ end
53
+ ]
54
+
55
+
56
+ end#timeout
57
+ rescue Timeout::Error=>e
58
+ Ol << 'Timed out in RubyConsole!'
59
+ end#begin
60
+ end#def
61
+
62
+ # Send output
63
+ def send_it the_command
64
+ time_stamp = "-eor#{Time.now.usec}-"
65
+
66
+ the_command = "\
67
+ # Temporary hack for nuby 1.8.4
68
+ $out_bufr = defined?(StringIO) ? StringIO.new : ''
69
+ begin
70
+ #{the_command}
71
+ rescue Exception => e
72
+ puts e.message
73
+ end
74
+ # Temporary hack for nuby 1.8.4
75
+ out = $out_bufr.respond_to?(:string) ? $out_bufr.string : $out_bufr
76
+ puts '#{time_stamp}'
77
+ $stdout.print out
78
+ "
79
+
80
+ #the_command.gsub!(/$/, " # input!")
81
+ begin
82
+ @channel.send_data(the_command)
83
+ @session.loop 2 do |session|
84
+ # Return true, unless found output
85
+ @@output !~ /^#{time_stamp}$/ && @@output !~ /___CLOSED___/
86
+ end
87
+ rescue Exception => e
88
+ puts "too slow! #{e.message}"
89
+ end
90
+ end
91
+
92
+ def open_channel
93
+ @session = if @server
94
+ user, server, port = Remote.split_root @server
95
+ Remote.new_connection(user, server, port)
96
+ else
97
+ Net::SSH.start('localhost', ENV['USER'] || ENV['USERNAME'])
98
+ end
99
+ @channel = @session.open_channel do |ch|
100
+ ch.exec @console_command do |ch, success|
101
+ raise "could not execute command" unless success
102
+ # When console returns (prints) something
103
+ ch.on_data do |c, data|
104
+ # Use to debug problems / errors on server
105
+ # Ol << "data: #{data.inspect}"
106
+ RubyConsole.output << data
107
+ #print data
108
+ end
109
+
110
+ # "on_extended_data" is called when the process writes something to stderr
111
+ ch.on_extended_data do |c, type, data|
112
+ print "error: #{data}"
113
+ end
114
+ ch.on_close {
115
+ RubyConsole.output << "___CLOSED___"
116
+ }
117
+ end
118
+ end
119
+
120
+ end
121
+
122
+ def run the_command
123
+ connect unless @channel
124
+ send_it the_command
125
+ out = @@output
126
+ @@output = ""
127
+
128
+ # Remove up until beginning of output
129
+ out.sub!(/.*^.*\$stdout\.print out\n/m, '')
130
+ # Remove last line
131
+ out.sub!(/^.?.?.?-eor\d+-\n.*/, '')
132
+
133
+ out == "" ? "(no output)\n" : out
134
+ end
135
+
136
+ def console_command= to; @console_command = to; end
137
+ def console_command; @console_command; end
138
+
139
+ def self.run the_command
140
+ self[:irb].run the_command
141
+ end
142
+
143
+ def self.[] key
144
+ @@registered[key]
145
+ end
146
+
147
+ def self.register key, console_command='irb', server=nil
148
+ @@registered[key] = RubyConsole.new(console_command, server)
149
+ end
150
+
151
+ def self.at key, the_command
152
+ key = key.to_sym if key.is_a? String
153
+ console = self[key]
154
+ raise "No console has been defined for key '#{key}'." unless console
155
+ console.run the_command
156
+ end
157
+
158
+ def session
159
+ connect unless @channel
160
+ @session
161
+ end
162
+
163
+ end
164
+
165
+ RubyConsole.register(:irb, 'irb')
@@ -0,0 +1,1572 @@
1
+ require "hide"
2
+ require 'control_lock'
3
+ require 'line'
4
+ require 'text_util'
5
+
6
+ class Search
7
+
8
+ SPECIAL_ORDER = "X!='\"[]{}<>_-+*@#\\/!$X"
9
+
10
+ @@case_options = nil
11
+ @@outline_goto_once = nil
12
+
13
+ @@log = File.expand_path("~/.emacs.d/search_log.notes")
14
+
15
+ def self.menu
16
+ '
17
+ - .history/
18
+ - .log/
19
+ - .launched/
20
+ - docs/
21
+ | > Summary
22
+ | You start a search by typing Control-s. Then type the search string.
23
+ | Here are some interesting keys to type while searching, to do things
24
+ | with the match.
25
+ |
26
+ | > What do we mean by "search_bookmark" etc.?
27
+ | With all xiki keyboard shorcuts, you "type the acronym".
28
+ | By the key shortcut "search_bookmark" we mean typing Control-s and then
29
+ | Control-c.
30
+ |
31
+ | Of course, typing Control-s to search lets you type characters
32
+ | to search for, so in some cases typing a search string in between makes
33
+ | sense. So, search_clipboard actually means you would type Control-s then
34
+ | some characters to search for then Control-c to copy to the clipboard.
35
+ |
36
+ | > Examples
37
+ - examples/
38
+ | search_copy: Copy found to clipboard
39
+ | search_bookmark: Search text of files in a dir
40
+ | search_all: Show all previous searches
41
+ | search_value: Insert found where search began
42
+ | search_delete: Delete found
43
+ | search_diffs (without searching): Search in diffs
44
+ | search_todo: Search in $t bookmark
45
+ | search_files: Search in $f bookmark
46
+ | search_paths: Search history of menus
47
+ - miscellaneous/
48
+ | search_search: Re-do the last search
49
+ | search_word: Suck the next word in
50
+ | search_yank: Suck the rest of the line in
51
+ | search_usurp: Suck the next expression in
52
+ |
53
+ | For more details about Xiki keyboard shortcuts, see:
54
+ - @keys/docs/
55
+ |
56
+ - see/
57
+ <@ next/
58
+ '
59
+ end
60
+
61
+ def self.case_options
62
+ return @@case_options if @@case_options
63
+ @@case_options = [] # Set to empty if not set yet
64
+ self.add_case_option 'upper', proc {|txt| txt.upcase}
65
+ self.add_case_option 'lower', proc {|txt| txt.downcase}
66
+ self.add_case_option 'camel', proc {|txt| TextUtil.camel_case(txt)}
67
+ self.add_case_option 'snake', proc {|txt| TextUtil.snake_case(txt)}
68
+ @@case_options
69
+ end
70
+
71
+ # Make another option show up for View.cases
72
+ def self.add_case_option name, the_proc
73
+ # Delete if there already
74
+ @@case_options.delete_if{|i| i.first == name}
75
+ @@case_options << [name, the_proc]
76
+ end
77
+
78
+ def self.insert_at_spot
79
+ match = self.stop
80
+ Hide.show
81
+
82
+ Location.to_spot
83
+
84
+ $el.insert match
85
+ end
86
+
87
+ def self.insert_tree_at_spot
88
+ self.stop
89
+ txt = FileTree.snippet # Grab symbol
90
+ Hide.show
91
+ Location.go :_0
92
+ $el.insert txt
93
+ end
94
+
95
+ def self.insert_at_search_start
96
+ was_reverse = self.was_reverse
97
+ match = self.stop
98
+
99
+ if match.nil? # If nothing searched for yet, search difflog
100
+ loc = Keys.input(:chars=>1, :prompt=>"Enter one char to search for corresponding string: ")
101
+ loc = loc.to_s
102
+
103
+ txt = Clipboard.hash[loc.to_s] || Clipboard.hash_by_first_letter[loc.to_s]
104
+ txt ||= self.searches.find{|o| o =~ /^#{loc}/i}
105
+
106
+ return View.message("Nothing to search for matching '#{loc}'.", :beep=>1) if txt.nil?
107
+ self.isearch txt, :reverse=>was_reverse
108
+
109
+ return
110
+ end
111
+
112
+ self.to_start # Go back to start
113
+ $el.insert match
114
+ end
115
+
116
+ def self.isearch_have_within
117
+ match = self.stop
118
+ self.to_start # Go back to start
119
+ $el.insert match[/^.(.*).$/, 1]
120
+ end
121
+
122
+ def self.move_to_search_start match
123
+ was_reverse = self.was_reverse
124
+ View.delete(Search.left, Search.right)
125
+
126
+ deleted = View.cursor
127
+ self.to_start # Go back to start
128
+ Move.backward match.length if was_reverse # If reverse, move back width of thing deleted
129
+
130
+ View.insert match
131
+
132
+ # Save spot where it was deleted (must do after modification, for bookmark to work)
133
+ View.cursor = deleted
134
+ Move.forward(match.length) unless was_reverse
135
+ Location.as_spot('killed')
136
+
137
+ self.to_start # Go back to start
138
+ Move.forward(match.length) unless was_reverse
139
+ end
140
+
141
+ def self.insert_var_at_search_start
142
+ match = self.stop
143
+ self.to_start # Go back to start
144
+ $el.insert "\#{#{match}}"
145
+ end
146
+
147
+ def self.insert_quote_at_search_start
148
+ match = self.stop
149
+ self.to_start
150
+ $el.insert "'#{match}'"
151
+ end
152
+
153
+ def self.isearch_select_inner
154
+ self.stop
155
+ $el.set_mark self.left + 1
156
+ $el.goto_char self.right - 1
157
+ Effects.blink :what=>:region
158
+ end
159
+
160
+ def self.isearch_delete
161
+ match = self.stop
162
+
163
+ # If nothing searched for, go to spot of last delete
164
+ if match.nil? # If nothing searched for yet, search difflog
165
+ DiffLog.open
166
+ View.to_bottom
167
+ Search.isearch nil, :reverse=>true
168
+ else
169
+ View.delete(Search.left, Search.right)
170
+ Location.as_spot('killed')
171
+ end
172
+ end
173
+
174
+ def self.enter txt=nil
175
+ match = self.stop
176
+ txt ||= Clipboard[0]
177
+
178
+ if match.nil? # If nothing searched for yet, do search_edits
179
+ bm = Keys.input :timed=>true, :prompt=>"Enter a bookmark to search edits: "
180
+
181
+ return Launcher.open("diff log/diffs/") if bm == "8" || bm == " "
182
+
183
+ path = bm == "." ? View.file : "$#{bm}/"
184
+ return Launcher.open("- #{path}\n @edits/")
185
+ end
186
+
187
+ View.delete(Search.left, Search.right)
188
+ View.insert txt
189
+ end
190
+
191
+ def self.copy_and_comment
192
+ self.stop
193
+ line = Line.value(1, :include_linebreak=>true).sub("\n", "")
194
+ Code.comment Line.left, Line.right
195
+ self.to_start # Go back to start
196
+ $el.insert "#{line}"
197
+ Line.to_beginning
198
+ end
199
+
200
+ def self.isearch_just_comment
201
+ self.stop
202
+ Code.comment Line.left, Line.right
203
+ Line.to_beginning
204
+ end
205
+
206
+ def self.just_increment options={}
207
+
208
+ match = self.stop
209
+
210
+ View.delete(Search.left, Search.right)
211
+
212
+ orig = View.cursor
213
+
214
+ position = SPECIAL_ORDER.index match
215
+
216
+ # If one of certain chars, use custom order
217
+ result =
218
+ if position # Change '[' to ']', etc
219
+
220
+ increment_or_decrement = options[:decrement] ? -1 : 1
221
+ SPECIAL_ORDER[position+increment_or_decrement].chr
222
+
223
+ else
224
+ if options[:decrement]
225
+ match =~ /[a-z]/i ?
226
+ (match[0] - 1) :
227
+ (match.to_i - 1).to_s
228
+ else
229
+
230
+ match.next
231
+ end
232
+ end
233
+
234
+ View.insert(result)
235
+ View.cursor = orig
236
+ end
237
+
238
+ def self.jump_to_difflog
239
+ match = self.stop
240
+ self.to_start
241
+ Location.as_spot
242
+
243
+ DiffLog.open
244
+ View.to_bottom
245
+
246
+ Search.isearch match, :reverse=>true
247
+ end
248
+
249
+ def self.just_edits
250
+ match = self.stop
251
+ DiffLog.open View.file
252
+ View.to_bottom
253
+
254
+ Search.isearch match, :reverse=>true
255
+ end
256
+
257
+ def self.copy match
258
+ Clipboard[0] = match
259
+ $el.set_register ?X, match
260
+ $el.x_select_text match
261
+ Clipboard.save_by_first_letter match # Store for retrieval with enter_yank
262
+ end
263
+
264
+ def self.cut
265
+ match = self.stop
266
+
267
+ # If nothing searched for, go to spot of last delete
268
+ if match.nil? # If nothing searched for yet
269
+ Location.to_spot('killed')
270
+ else
271
+ Clipboard.set(0, match)
272
+ $el.set_register ?X, match
273
+ View.delete self.left, self.right
274
+ Location.as_spot('killed')
275
+ end
276
+ end
277
+
278
+ def self.go_to_end
279
+ match = self.stop
280
+
281
+ if match.nil? # If nothing searched for yet
282
+ Search.isearch_restart "$f", :restart=>true
283
+ return
284
+ end
285
+
286
+ $el.goto_char self.right
287
+ end
288
+
289
+ # Clears the isearch, allowing for inserting, or whatever else
290
+ def self.stop options={}
291
+
292
+ left, right = self.left, self.right
293
+
294
+ txt = self.match(left, right)# if options[:match]
295
+
296
+ # Make it do special clear if nothing found (to avoid weird isearch error)
297
+ if txt.nil?
298
+ if $el.elvar.isearch_success # || Search.left == View.bottom
299
+ # Done so isearch_done won't error
300
+ $el.isearch_resume "[^`]", true, nil, true, "", true
301
+ View.message ""
302
+ else
303
+ txt = :not_found
304
+ end
305
+ end
306
+
307
+ $el.elvar.isearch_mode = nil
308
+
309
+ $el.isearch_clean_overlays
310
+ $el.isearch_done
311
+
312
+ txt == :not_found ? Search.last_search : txt
313
+ end
314
+
315
+ def self.match left=nil, right=nil
316
+ left ||= self.left
317
+ right ||= self.right
318
+
319
+ return nil if left == 0# || self.nil?
320
+ result = $el.buffer_substring(left, right)
321
+
322
+ return nil if result == ""
323
+ result
324
+ end
325
+
326
+ def self.to_start
327
+ View.to($el.elvar.isearch_opoint)
328
+ end
329
+
330
+ # Do query replace depending on what they type
331
+ def self.query_replace s1=nil, s2=nil
332
+ if s1 && s2 # If manually passed in
333
+ $el.query_replace_regexp($el.regexp_quote(s1 || ""), s2 || "")
334
+ return
335
+ end
336
+
337
+ first = Keys.input(:timed=>true)
338
+ # If they typed 'o', use clipboard 1 and clipboard 2
339
+ if first == "o" || first == "1"
340
+ $el.query_replace_regexp($el.regexp_quote(Clipboard.get("1")), Clipboard.get("2"))
341
+ # If they typed 't', use clipboard 2 and clipboard 1
342
+ elsif first == "t" || first == "2"
343
+ $el.query_replace_regexp(Clipboard.get("2"), Clipboard.get("1"))
344
+ # If 'q', prompt for both args
345
+ elsif first == "q"
346
+ $el.query_replace_regexp(
347
+ Keys.input(:prompt=>"Replace: "),
348
+ Keys.input(:prompt=>"With: "))
349
+ # If they typed 'c', use clipboard and prompt for 2nd arg
350
+ elsif first == "c"
351
+ $el.query_replace_regexp(Clipboard.get, Keys.input(:prompt=>"Replace with (pause when done): ", :timed=>true))
352
+ # If they typed 'c', use clipboard and prompt for 2nd arg
353
+ elsif first == "l"
354
+ $el.query_replace_regexp(@@query_from, @@query_to)
355
+ # Otherwise, just get more input and use it
356
+ else
357
+ $el.query_replace_regexp(first, Keys.input(:timed=>true))
358
+ end
359
+ nil
360
+ end
361
+
362
+ def self.isearch_query_replace after=nil
363
+ match = self.stop#
364
+ was_upper = match =~ /[A-Z]/
365
+
366
+ match.downcase!
367
+ left, right = Search.left, Search.right
368
+ before = $el.regexp_quote(match) # Always start with isearch match
369
+
370
+ # If before not there or is :match, prompt for input
371
+ if after.nil? || after == :match
372
+ initial_input = after == :match ? before : ''
373
+ after = Keys.input(:prompt=>"Change instances of '#{before}' to: ", :initial_input=>initial_input)
374
+ @@query_from, @@query_to = before, after
375
+ end
376
+
377
+ View.delete left, right
378
+ View.insert was_upper ?
379
+ TextUtil.title_case(after) :
380
+ after
381
+
382
+ $el.query_replace_regexp before, after
383
+ end
384
+
385
+ def self.grep
386
+ cm_grep("./", read_from_minibuffer("Grep for pattern: "))
387
+ end
388
+
389
+ def self.tree_grep # prefix=nil
390
+
391
+ prefix = Keys.isearch_prefix
392
+ path = Keys.bookmark_as_path :include_file=>1 # Get path (from bookmark)
393
+
394
+ # If C-u, just jump to bookmark and search from the top
395
+ if prefix == :u
396
+ View.open path
397
+ View.to_highest
398
+ Search.isearch
399
+ return
400
+ end
401
+
402
+ if path == :space # If space, search in buffers
403
+ self.find_in_buffers Keys.input(:prompt=>"Search all open files for: ")
404
+ return
405
+ end
406
+
407
+ input = Keys.input(:prompt=>"Text to search for: ")
408
+
409
+ input.gsub! "#", "\\#"
410
+
411
+ FileTree.grep_with_hashes path, input
412
+ end
413
+
414
+ # Incrementeal search between cursor and end of paragraph (kills unmatching lines)
415
+ def self.kill_search(left, right)
416
+ pattern = ""
417
+ lines = $el.buffer_substring(left, right).split "\n"
418
+ ch = $el.char_to_string read_char
419
+ while ch =~ /[~#-'>a-zA-Z0-9!*\_'.~#-\/]/
420
+ if ch == "\t"
421
+ pattern = ""
422
+ else
423
+ pattern = pattern + regexp_quote(ch)
424
+ # Filter text and put back
425
+ View.delete left, right
426
+ # Replace out lines that don't match
427
+ lines = lines.grep(/#{pattern}/i)
428
+ # Put back into buffer
429
+ $el.insert lines.join("\n") + "\n"
430
+ right = $el.point
431
+ # Go to first file
432
+ $el.goto_char left
433
+ end
434
+ $el.message "Delete lines not matching: %s", pattern
435
+ ch = $el.char_to_string read_char
436
+ end
437
+ # Run whatever they typed last as a command (it was probably C-m or C-a, etc.)
438
+ case ch
439
+ when "\C-m" # If it was C-m
440
+ # Do nothing
441
+ else
442
+ $el.command_execute ch
443
+ end
444
+ end
445
+
446
+ def self.search_in_bookmark match
447
+
448
+ bm = Keys.bookmark_as_path :include_file=>1
449
+
450
+ if bm == :slash # If space, go back to root and search
451
+ # Make match be orange
452
+ Overlay.face(:ls_search, :left=>self.left, :right=>self.right)
453
+ self.search_at_root match
454
+ return
455
+ end
456
+
457
+ View.to_after_bar if View.in_bar?
458
+
459
+ if bm == :space # If space, search in buffers
460
+ self.find_in_buffers match
461
+ return
462
+ end
463
+
464
+ match.gsub!(/([#()*+?^$\[\]|.])/, "\\\\\\1")
465
+ match.gsub! "\\+", "." # Change + to . to help when searching for key shortcuts
466
+
467
+ # Search in bookmark
468
+ FileTree.grep_with_hashes bm, match
469
+ end
470
+
471
+
472
+ def self.subtract
473
+ match = self.match
474
+
475
+ if match # If currently searching
476
+ return $el.isearch_del_char
477
+ end
478
+
479
+ View.message "Unused!", :beep=>1
480
+
481
+ self.stop
482
+ self.search_last_launched
483
+ end
484
+
485
+ def self.search_last_launched
486
+ match = self.stop
487
+
488
+ Launcher.open Launcher.last_launched_menu
489
+ end
490
+
491
+ def self.launched bm=nil
492
+
493
+ txt = File.read @@log
494
+ txt = txt.sub(/\A- /, '').split(/^- /).reverse.uniq
495
+ if bm && bm == "#"
496
+ txt = txt.select{|o| o =~ /^ - ##/}
497
+ elsif bm && bm == ":"
498
+ txt = txt.select{|o| o =~ /^ - [^#].*: /}
499
+ elsif bm
500
+
501
+ path = Bookmarks[bm]
502
+
503
+ if File.file? path # File
504
+ regex = /^#{Regexp.escape File.dirname path}\/\n - #{Regexp.escape File.basename path}/
505
+ else # Dir
506
+ regex = /^#{Regexp.escape path}/
507
+ path = "#{path}/" if path !~ /\/$/
508
+ end
509
+
510
+ txt = txt.select{|o| o =~ regex}
511
+ end
512
+
513
+ result = "- @#{txt.join("- @")}"
514
+ result
515
+ end
516
+
517
+ def self.left
518
+ $el.match_beginning 0
519
+ end
520
+
521
+ def self.right
522
+ $el.match_end 0
523
+ end
524
+
525
+ def self.isearch_find_in_buffers options={}
526
+ match = self.stop
527
+ self.find_in_buffers match, options
528
+ end
529
+
530
+ def self.find_in_buffers string, options={}
531
+ string.gsub!('"', '\\"')
532
+ new_args = "\"#{string}\""
533
+ new_options = {}
534
+ new_options[:buffer] = View.buffer_name if options[:current_only]
535
+ new_args << ", #{new_options.inspect[1..-2]}" unless new_options.empty?
536
+
537
+ View.bar if options[:in_bar]
538
+ $el.switch_to_buffer "*tree find in buffers"
539
+ Notes.mode
540
+ $el.erase_buffer
541
+
542
+ View.insert "+ Buffers.search #{new_args}/"
543
+ $el.open_line 1
544
+ CodeTree.launch :no_search=>true
545
+ if new_options[:buffer] # Goto first match
546
+ $el.goto_line 4
547
+ Line.to_words
548
+ Tree.search(:recursive=>false, :left=>Line.left, :right=>View.bottom)
549
+ else # Goto first match in 2nd file
550
+ $el.goto_line 2
551
+ $el.re_search_forward "^ -", nil, true
552
+ Line.next 2
553
+ Line.to_words
554
+ end
555
+ end
556
+
557
+ def self.just_marker
558
+ match = self.stop
559
+
560
+ $el.highlight_regexp(Regexp.quote(match), :notes_label)
561
+ end
562
+
563
+ def self.highlight_found
564
+ match = self.stop
565
+
566
+ $el.highlight_regexp(Regexp.quote(match), :hi_yellow)
567
+ end
568
+
569
+ def self.hide
570
+ match = self.stop
571
+ Hide.hide_unless /#{Regexp.quote(match)}/i
572
+ $el.recenter -3
573
+ Hide.search
574
+ end
575
+
576
+ # Insert line at beginning of search
577
+ def self.have_line
578
+ self.stop
579
+ line = Line.value(1, :include_linebreak=>true).sub("\n", "")
580
+ self.to_start # Go back to start
581
+ $el.insert line
582
+ end
583
+
584
+ # Insert line at beginning of search
585
+ def self.have_label
586
+ self.stop
587
+ label = Line.label
588
+ self.to_start # Go back to start
589
+ $el.insert "- #{label}: "
590
+ end
591
+
592
+ # Insert line at beginning of search
593
+ def self.have_paragraph
594
+ self.stop
595
+ paragraph = View.paragraph
596
+ offset = View.cursor - View.paragraph(:bounds=>true)[0]
597
+ self.to_start # Go back to start
598
+ orig = Location.new
599
+ $el.insert paragraph
600
+ orig.go
601
+ Move.forward offset
602
+ end
603
+
604
+
605
+ # During isearch, pull next n words
606
+ def self.isearch_pull_in_words n
607
+ # If on the beginning of a grouping char, move back to catch the sexp
608
+ $el.el4r_lisp_eval "
609
+ (isearch-yank-internal
610
+ (lambda ()
611
+ (forward-word #{n}) (point)))"
612
+ end
613
+
614
+ # During isearch, pull next sexp into the search string
615
+ def self.isearch_pull_in_sexp
616
+ # If on the beginning of a grouping char, move back to catch the sexp
617
+
618
+ $el.el4r_lisp_eval %q=
619
+ (isearch-yank-internal
620
+ (lambda ()
621
+ (if (and (> (point) 1)
622
+ (string-match "[{<\\\\\"'(\\\\[]" (char-to-string (char-before (point))))
623
+ )
624
+ (backward-char))
625
+ (forward-sexp) (point)))=
626
+
627
+ end
628
+
629
+ # During isearch, open most recently edited file with the search string in its name
630
+ def self.isearch_to
631
+ match = self.stop
632
+
633
+ if match.nil? # If nothing searched for yet
634
+ Search.isearch_restart "$t", :restart=>true
635
+
636
+ else
637
+ dir = Keys.bookmark_as_path :prompt=>"Enter bookmark to look in (or space for recently edited): "
638
+
639
+ return View.message("Use space!", :beep=>1) if dir == :comma
640
+
641
+ return self.open_file_and_method(match) if dir == :space # If key is comma, treat as last edited
642
+
643
+ TextUtil.snake_case! match if match =~ /[a-z][A-Z]/ # If camel case, file is probably snake
644
+ FileTree.grep_with_hashes dir, match, '**' # Open buffer and search
645
+ end
646
+ end
647
+
648
+ #
649
+ # Jumps to the file corresponding to a string.
650
+ # The string has no path - the edited history (and visited history?)
651
+ # are used to find the file.
652
+ #
653
+ # If the string is like "Foo.bar" it jumps to the method as well ("foo").
654
+ #
655
+ # > Examples
656
+ # Search.open_file_and_method "View"
657
+ # Search.open_file_and_method "View.path"
658
+ #
659
+ def self.open_file_and_method match
660
+
661
+ match.sub!(/^[+-] /, '')
662
+ match.sub!(/ .+/, '')
663
+
664
+ if match =~ /(.+)[.#](.+)/
665
+ match, method = $1, $2 # split off, and open
666
+ end
667
+
668
+ # Convert to snake case, or nil if already in snake case
669
+ snake = TextUtil.snake_case(match)
670
+ snake = nil if snake == match
671
+
672
+ match = "#{match}."
673
+ snake = "#{snake}."
674
+ # For each file edited
675
+ found = (Files.edited_array + Files.history_array).find do |o|
676
+
677
+ next if o =~ /.notes$/ # Ignore notes files
678
+ next if o =~ /:/ # Ignore files with colons (tramp)
679
+ name = o[/.*\/(.*)/, 1] # Strip off path
680
+ # Check for match
681
+ if name =~ /^#{Regexp.quote(match)}/i || (snake && name =~ /^#{Regexp.quote(snake)}/i)
682
+ o
683
+ else
684
+ false
685
+ end
686
+ end
687
+
688
+ if found # Open it if it matches
689
+ View.open found
690
+ if method # If method, go to it
691
+ View.to_highest
692
+ result = Search.forward "^ +def \\(self\\.\\)?#{method}[^_a-zA-Z0-9]", :beginning=>true
693
+
694
+ return Code.suggest_creating_method View.file, method if !result # If not found, suggest creating
695
+
696
+ Move.to_axis
697
+ $el.recenter 0
698
+
699
+ dir, name = found.match(/(.+\/)(.+)/)[1..2]
700
+ Search.append_log dir, "- #{name}\n | #{Line.value}"
701
+
702
+ end
703
+ else
704
+ View.message "'#{match}' not found (no recently edited file with that substring found)."
705
+ end
706
+
707
+ return
708
+
709
+ end
710
+
711
+ def self.isearch_or_copy name
712
+ was_reverse = self.was_reverse
713
+ match = self.stop
714
+
715
+ if match.nil? # If nothing searched for yet
716
+ self.isearch Clipboard[name].downcase, :reverse=>was_reverse
717
+ else # Else, if nothing searched for
718
+ self.stop
719
+ Clipboard[name] = match
720
+ end
721
+ end
722
+
723
+ def self.isearch_copy_as name
724
+ self.stop
725
+ Clipboard.set(name, self.match)
726
+ end
727
+
728
+ def self.kill_filter options={}
729
+ # TODO: Get options[:kill_matching]=>true to delete matching
730
+ # - and map to Keys.do_kill_matching
731
+ Line.start
732
+ left = $el.point
733
+ $el.re_search_forward "^$", nil, 1
734
+ right = $el.point
735
+ $el.goto_char left
736
+ Tree.search(:left=>left, :right=>right, :recursive=>true)
737
+ end
738
+
739
+ def self.cancel
740
+ self.stop
741
+ self.to_start # Go back to start
742
+ end
743
+
744
+ # def self.not_found?
745
+ # # Note this returns false when nothing searched for
746
+
747
+ # ! elvar.isearch_success
748
+ # end
749
+
750
+ def self.forward search, options={}
751
+ View.to_highest if options[:from_top]
752
+
753
+ orig = View.cursor
754
+ found = $el.re_search_forward search, nil, (options[:go_anyway] ? 1 : true)
755
+ View.cursor = orig if options[:dont_move]
756
+ View.cursor = self.left if options[:beginning] && View.cursor != View.bottom
757
+
758
+ found
759
+ end
760
+
761
+ def self.backward search, options={}
762
+ orig = View.cursor
763
+ found = $el.re_search_backward search, nil, (options[:go_anyway] ? 1 : true)
764
+ View.cursor = orig if options[:dont_move]
765
+ found
766
+ end
767
+
768
+ def self.to find
769
+ Move.forward
770
+ if Search.forward(find)
771
+ match = $el.buffer_substring self.left, self.right
772
+ Move.backward(match.size)
773
+ else
774
+ $el.beep
775
+ $el.message "not found"
776
+ Move.backward
777
+ end
778
+ end
779
+
780
+ def self.isearch_open
781
+ self.stop
782
+ View.open(self.match)
783
+ end
784
+
785
+ def self.isearch_google options={}
786
+ term = self.stop
787
+ if term
788
+ term.gsub!(' ', '+')
789
+
790
+ term = "\"#{term}\"" if options[:quote]
791
+
792
+ term =~ /^https?:\/\// ? # If url, just browse
793
+ $el.browse_url(term) :
794
+ $el.browse_url("http://google.com/search?q=#{term}")
795
+ return
796
+ end
797
+
798
+ Firefox.log
799
+ Search.isearch nil, :from_bottom=>true
800
+
801
+ end
802
+
803
+ def self.search_thesaurus
804
+ term = self.stop
805
+
806
+ url = term.sub(/^\s+/, '').gsub('"', '%22').gsub(':', '%3A').gsub(' ', '%20')
807
+ $el.browse_url "http://thesaurus.reference.com/browse/#{url}"
808
+ end
809
+
810
+ def self.isearch_move_line
811
+ $el.isearch_done
812
+ $el.isearch_clean_overlays
813
+ line = $el.buffer_substring $el.point_at_bol, $el.point_at_eol + 1
814
+ View.delete $el.point_at_bol, $el.point_at_eol + 1
815
+ #self.to_start # Go back to start
816
+ $el.exchange_point_and_mark
817
+ $el.insert line
818
+ end
819
+
820
+ def self.outline
821
+ if Keys.prefix_u?
822
+ History.open_current :outline => true, :prompt_for_bookmark => true
823
+ else
824
+ History.open_current :outline => true
825
+ end
826
+ end
827
+
828
+ def self.outline_search
829
+ if Keys.prefix_u?
830
+ History.open_current :bar=>true, :all=>true
831
+ else
832
+ History.open_current :all=>true
833
+ end
834
+ end
835
+
836
+ def self.upcase
837
+ self.stop
838
+ $el.upcase_region(self.left, self.right)
839
+ end
840
+
841
+ def self.downcase
842
+ self.stop
843
+ $el.downcase_region(self.left, self.right)
844
+ end
845
+
846
+ def self.enter_like_edits
847
+ Notes.enter_junior
848
+ View << "@edits/"
849
+ Launcher.launch
850
+ end
851
+
852
+ def self.enter_search bm=nil, input=nil
853
+ # If line already has something, assume we'll add - ##foo/ to it
854
+ if ! Line[/^ *$/]
855
+ input = Keys.prefix_u ? Clipboard.get : Keys.input(:prompt=>"Text to search for: ")
856
+ indent = Line.indent
857
+ Line.to_right
858
+ View.insert "\n#{indent} - ###{input}/"
859
+ Launcher.launch
860
+ return
861
+ end
862
+
863
+ bm ||= Keys.input(:timed=>true, :prompt=>"Enter bookmark in which to search: ")
864
+ return unless bm
865
+ input ||= Keys.prefix_u? ? # Do search
866
+ Clipboard.get :
867
+ Keys.input(:prompt=>"Text to search for: ")
868
+
869
+ if bm == "." # Do tree in dir from bookmark
870
+ if Line.blank?
871
+ dir = $el.elvar.default_directory
872
+ else
873
+ dir = nil
874
+ end
875
+ else
876
+ dir = Bookmarks.expand("$#{bm}")
877
+ end
878
+
879
+ View.insert("- #{dir}" || "")
880
+ indent = Line.indent
881
+ Line.to_right
882
+ View.insert("\n#{indent} - ###{input}/")
883
+ FileTree.launch
884
+
885
+ end
886
+
887
+ def self.isearch_have_output
888
+
889
+ return self.isearch_have_output_javascript if View.extension == "js"
890
+
891
+ match = self.stop
892
+ self.to_start
893
+ return View.insert("Ol.line") if match.nil?
894
+
895
+ if Tree.construct_path(:all=>1, :slashes=>1) =~ /<script/
896
+ View.insert "console.log('#{match}: ' + #{match});"
897
+ return
898
+ end
899
+
900
+ View.insert "Ol << \"#{match}: \#{#{match}.inspect}\""
901
+ end
902
+
903
+ def self.isearch_have_output_javascript
904
+ match = self.stop
905
+ self.to_start
906
+ View.insert "p(\"#{match}: \" + #{match});"
907
+ end
908
+
909
+ def self.isearch_as_camel
910
+ self.stop
911
+ term = self.match
912
+ self.to_start
913
+ View.insert TextUtil.camel_case(term)
914
+ end
915
+
916
+ def self.isearch_as_snake
917
+ self.stop
918
+ term = self.match
919
+ self.to_start
920
+ View.insert TextUtil.snake_case(term)
921
+ end
922
+
923
+ def self.isearch_just_adjust
924
+ self.stop
925
+ Move.forward
926
+ transpose_chars 1
927
+ self.to_start
928
+ end
929
+
930
+ # Go to root of tree and do search
931
+ def self.search_at_root txt
932
+ Search.backward("^ *[+-] /")
933
+ # If next line isn't ##... line (will be visually distinct) add linebreak
934
+ unless Line.value(2) =~ /^ *[+-] ##/
935
+ Line.next
936
+ View.insert "\n"
937
+ Line.previous 2
938
+ end
939
+ self.enter_search '.', txt
940
+ end
941
+
942
+ def self.just_select
943
+ self.stop
944
+ View.set_mark(Search.right)
945
+ View.to(Search.left)
946
+ Effects.blink :what=>:region
947
+ end
948
+
949
+ def self.isearch_just_tag
950
+ self.stop
951
+
952
+ left, right = Search.left, Search.right
953
+ tag = Keys.input :timed=>true, :prompt=>"Enter tag name: "
954
+ left_tag = "<#{tag}>"
955
+ right_tag = "</#{tag}>"
956
+ if tag == 'di'
957
+ left_tag = "<div id='#{Keys.input :prompt=>"Enter id: "}'>"
958
+ right_tag = "</div>"
959
+ elsif tag == 'dc'
960
+ left_tag = "<div class='#{Keys.input :prompt=>"Enter id: "}'>"
961
+ right_tag = "</div>"
962
+ end
963
+
964
+ View.to(right)
965
+ View.insert right_tag
966
+ View.to(left)
967
+ View.insert left_tag
968
+ View.to right + left_tag.length
969
+ end
970
+
971
+
972
+ def self.isearch_just_wrap
973
+ self.stop
974
+ left, right = Search.left, Search.right
975
+
976
+ wrap_with = Keys.input :timed=>true, :prompt=>"Enter string to wrap match with: "
977
+
978
+ View.to(right)
979
+ View.insert wrap_with
980
+ View.to(left)
981
+ View.insert wrap_with
982
+ View.to right + wrap_with.length
983
+ end
984
+
985
+
986
+ def self.just_orange
987
+ self.stop
988
+ Overlay.face(:notes_label, :left=>Search.left, :right=>Search.right)
989
+ end
990
+
991
+ def self.just_edges
992
+ self.stop
993
+ left, right = Search.left+1, Search.right-1
994
+ Effects.blink :left=>left, :right=>right
995
+ View.delete(left, right)
996
+ View.to(Search.left+1)
997
+ end
998
+
999
+ def self.isearch_just_surround_with_char left=nil, right=nil
1000
+
1001
+ right ||= left
1002
+ term = self.stop
1003
+
1004
+ if term == ""
1005
+ View.insert "()"
1006
+ Move.backward
1007
+ return
1008
+ end
1009
+
1010
+ View.to(Search.left + term.length)
1011
+ View.insert right
1012
+ View.to(Search.left)
1013
+ View.insert left
1014
+ View.to Search.left
1015
+ end
1016
+
1017
+
1018
+ def self.isearch_surround_with_tag
1019
+
1020
+ term = self.stop
1021
+ left = Search.left
1022
+
1023
+ tag = Keys.input :timed=>1, :prompt=>"Enter tag to surround: "
1024
+
1025
+ View.to(left + term.length)
1026
+ View.insert "</#{tag}>"
1027
+ View.to left
1028
+ View.insert "<#{tag}>"
1029
+ View.to left
1030
+ end
1031
+
1032
+ # Copy match as name (like Keys.as_name)
1033
+ def self.just_name
1034
+ term = self.stop
1035
+ loc ||= Keys.input(:chars=>1, :prompt=>"Enter one char (variable name to store this as): ") || "0"
1036
+ Clipboard.copy loc, term
1037
+ Effects.blink :left=>left, :right=>right
1038
+ end
1039
+
1040
+ def self.just_macro
1041
+ self.stop
1042
+ Macros.run
1043
+ end
1044
+
1045
+ def self.to_left
1046
+ match = self.stop
1047
+ if match.nil? # If nothing searched for yet
1048
+ return Launcher.open "- search/.history/", :bar_is_fine=>1
1049
+ end
1050
+
1051
+ Line.to_left
1052
+ end
1053
+
1054
+ def self.just_menu
1055
+ match = self.stop
1056
+ View.open "$ml"
1057
+ View.to_bottom
1058
+ Search.isearch match, :reverse=>true
1059
+ end
1060
+
1061
+ def self.isearch_just_case
1062
+ was_reverse = self.was_reverse
1063
+ txt = self.stop
1064
+
1065
+ return Search.isearch(Clipboard[0], :reverse=>was_reverse) if txt.nil?
1066
+
1067
+ choice = Keys.input(:prompt=>'convert to which case?: ', :choices=>TextUtil.case_choices)
1068
+ View.delete(Search.left, Search.right)
1069
+ View.insert choice[txt]
1070
+ end
1071
+
1072
+ def self.isearch_have_case
1073
+ self.stop
1074
+ txt = self.match
1075
+ lam = Keys.input(:prompt=>'convert to which case?: ', :choices=>TextUtil.case_choices)
1076
+ self.to_start # Go back to start
1077
+ $el.insert lam[txt]
1078
+ end
1079
+
1080
+ def self.isearch_just_underscores
1081
+ self.stop
1082
+ term = self.match
1083
+ View.delete(Search.left, Search.right)
1084
+ View.insert TextUtil.snake_case(term)
1085
+ end
1086
+
1087
+ @@zap_hooks ||= {}
1088
+ # To set a hook
1089
+ # Search.zap_hooks 'm' do ... end
1090
+ def self.zap_hooks # key, &block
1091
+ @@zap_hooks#[key] = value
1092
+ end
1093
+
1094
+ def self.zap
1095
+ match = self.stop
1096
+
1097
+ if match.nil? # If nothing searched for yet
1098
+ char = Keys.input(:chars=>1, :prompt=>"Enter one char: ")
1099
+ block = self.zap_hooks[char]
1100
+ return View.beep "- search+zap+#{char}... doesn't seem to be defined!" if block.nil?
1101
+ return block.call
1102
+ end
1103
+
1104
+ right = $el.point
1105
+ self.to_start # Go back to search start
1106
+ View.delete($el.point, right)
1107
+ end
1108
+
1109
+ def self.xiki
1110
+ match = self.stop
1111
+
1112
+ View.beep "- Don't know what to do when search+x with search match." if match
1113
+
1114
+ char = Keys.input(:chars=>1, :prompt=>"Enter one char: ")
1115
+ if char == "m"
1116
+ Launcher.open("- $x/\n - ##\\bdef /")
1117
+ elsif char == "k"
1118
+ Launcher.open("- $x/key_bindings.rb\n - ##\\bKeys\\./")
1119
+ elsif char == "l"
1120
+ Launcher.open("- $ttm\n - ##xiki|isearch/")
1121
+ else
1122
+ View.beep "Don't know what to do with that char."
1123
+ end
1124
+
1125
+ end
1126
+
1127
+ def self.isearch_restart path, options={}
1128
+ self.stop
1129
+ term = Search.last_search
1130
+
1131
+ if path == "$t" # If $t, open bar
1132
+ View.layout_todo
1133
+ # FileTree.open_in_bar; Effects.blink(:what=>:line)
1134
+ elsif path == "$f"
1135
+ View.layout_files
1136
+ elsif path == "$o"
1137
+ View.layout_output
1138
+ options[:reverse] = true
1139
+ elsif path == "$d"
1140
+ View.open "$d"
1141
+ options[:reverse] = true
1142
+ elsif path == :top
1143
+ # Will go to highest below
1144
+ elsif path == :right
1145
+ View.layout_right 1
1146
+ elsif path == :next
1147
+ View.next
1148
+ elsif path == :previous
1149
+ View.previous
1150
+ else
1151
+ View.open Bookmarks[path]
1152
+ end
1153
+
1154
+ View.wrap unless options[:restart] # Don't change wrapping if starting search
1155
+ View.to_highest
1156
+
1157
+ if options[:reverse]
1158
+ View.to_bottom
1159
+ options[:restart] ? $el.isearch_backward : self.isearch(term, :reverse=>true)
1160
+ return
1161
+ end
1162
+
1163
+ options[:restart] ? $el.isearch_forward : self.isearch(term)
1164
+ end
1165
+
1166
+ def self.isearch txt=nil, options={}
1167
+
1168
+ if options[:from_bottom]
1169
+ View.to_bottom
1170
+ options[:reverse] = true
1171
+ end
1172
+
1173
+ txt ||= "" # Searchig for nil causes error
1174
+ $el.isearch_resume txt, (options[:regex] ?true:nil), nil, (! options[:reverse]), txt, true
1175
+ $el.isearch_update
1176
+ end
1177
+
1178
+ def self.isearch_stop_at_end
1179
+ # Kind of a hack - search for anything, so it won't error when we stop
1180
+ $el.isearch_resume "[^`]", true, nil, true, "", true
1181
+
1182
+ self.stop
1183
+ self.to_start # Go back to start
1184
+
1185
+ View.message ""
1186
+ nil
1187
+ end
1188
+
1189
+ def self.isearch_outline
1190
+ match = self.stop
1191
+
1192
+ if match.nil? # If nothing searched for yet
1193
+ # Do isearch in Ol buffer
1194
+ Search.isearch_restart "$o", :restart=>true
1195
+
1196
+ else
1197
+ if ! View.file # If buffer, not file
1198
+ buffer_name = $el.buffer_name
1199
+ txt = View.txt
1200
+ View.to_buffer "* outline of matches in #{buffer_name}"
1201
+ Notes.mode
1202
+ View.kill_all
1203
+ View.insert txt.grep(Regexp.new(match)).join
1204
+
1205
+ return
1206
+ end
1207
+
1208
+ # If file
1209
+
1210
+ Search.outline_goto_once = Line.number
1211
+
1212
+ dir = View.dir
1213
+ file_name = View.file_name
1214
+ View.to_buffer "*tree grep"; View.dir = dir
1215
+ View.clear; Notes.mode
1216
+ View.insert "
1217
+ - #{dir}/
1218
+ - #{file_name}
1219
+ - ###{Regexp.quote(match)}/
1220
+ ".unindent
1221
+
1222
+ View.to_line 3
1223
+ FileTree.launch
1224
+
1225
+ # Search.isearch_find_in_buffers(:current_only=>true)
1226
+ end
1227
+ end
1228
+
1229
+ def self.isearch_paths
1230
+ was_reverse = self.was_reverse
1231
+ match = self.stop
1232
+ return Line.previous if match.nil? && was_reverse # Odd case, user might do this if at end of file
1233
+ return Git.search_repository if match.nil?
1234
+
1235
+ Search.move_to_search_start match
1236
+ end
1237
+
1238
+ def self.isearch_next
1239
+ was_reverse = self.was_reverse
1240
+ match = self.stop
1241
+ if match.nil? && Keys.before_last == "19" # If nothing searched for yet
1242
+ self.stop
1243
+ self.search_last_launched
1244
+ else
1245
+
1246
+ self.stop
1247
+ $el.next_line
1248
+ end
1249
+ end
1250
+
1251
+ def self.was_reverse
1252
+ ! $el.elvar.isearch_forward
1253
+ end
1254
+
1255
+ def self.isearch_clipboard
1256
+ txt = Search.stop
1257
+
1258
+ if txt.nil? # If nothing searched for yet
1259
+ Console.search_last_commands
1260
+ else
1261
+ self.copy txt
1262
+ Location.as_spot('clipboard')
1263
+ end
1264
+ end
1265
+
1266
+ def self.isearch_pause_or_resume
1267
+ match = self.stop
1268
+
1269
+ if match.nil? # If nothing searched for yet, resume search
1270
+ Location.to_spot('paused')
1271
+ Search.isearch $xiki_paused_isearch_string
1272
+ else
1273
+ # If search in progress, stop it, remembering spot
1274
+ $xiki_paused_isearch_string = self.match.downcase
1275
+ Location.as_spot('paused')
1276
+ end
1277
+ end
1278
+
1279
+ def self.isearch_just_search
1280
+ self.just_orange
1281
+ match = self.match
1282
+
1283
+ Tree.to_parent # Go to parent
1284
+ Tree.to_parent if Line[/^ *- ##/]
1285
+
1286
+ Tree.under "- \#\##{match}/", :escape=>'', :no_search=>true
1287
+ Launcher.launch
1288
+ end
1289
+
1290
+ def self.isearch_enter_and_next
1291
+ if self.match == "" # If nothing searched for yet, go to where last copy happened
1292
+ self.stop
1293
+ Location.to_spot('clipboard')
1294
+ Search.isearch Clipboard[0]
1295
+ return
1296
+ end
1297
+
1298
+ match = self.stop
1299
+ View.delete(Search.left, Search.right)
1300
+ View.insert Clipboard[0]
1301
+ Search.isearch match
1302
+ end
1303
+
1304
+ def self.isearch_move_to path, options={}
1305
+ match = self.stop
1306
+ match = Line.value if match.nil? # Use line if nothing searched for
1307
+ self.move_to path, match, options
1308
+ end
1309
+
1310
+
1311
+ def self.move_to_files match
1312
+ match_with_path = FileTree.snippet :txt=>match
1313
+ match_with_path = ">\n- #{match_with_path}"
1314
+
1315
+ result = self.fit_in_snippet match
1316
+ result ? nil : match_with_path
1317
+ end
1318
+
1319
+ def self.fit_in_snippet match
1320
+
1321
+ target_path = View.file
1322
+ View.layout_files :no_blink=>1
1323
+
1324
+ View.to_highest
1325
+ Move.to_junior # Go to first file
1326
+
1327
+ path = Xiki.trunk.last # Grab from wiki tree
1328
+
1329
+ # If doesn't fit in the tree, just return to delegate back
1330
+ return false if ! target_path || ! target_path.start_with?(path)
1331
+
1332
+ cursor = Line.left 2
1333
+ FileTree.enter_quote match
1334
+ View.cursor = cursor
1335
+
1336
+ return true # If handled
1337
+ end
1338
+
1339
+
1340
+ def self.move_to path, match, options={}
1341
+ orig = Location.new
1342
+ was_in_bar = View.in_bar?
1343
+
1344
+ if path == "$t" # If $f, grab path also
1345
+ View.layout_todo :no_blink=>1
1346
+ elsif path == "$f" # If $f, grab path also
1347
+ match = self.move_to_files match
1348
+ return orig.go if ! match # It handled it if it didn't return the match
1349
+ else
1350
+ View.open path
1351
+ end
1352
+
1353
+ # Maybe extract to .insert_in_section ?
1354
+ View.to_highest
1355
+
1356
+ line_occupied = ! Line.blank?
1357
+
1358
+ Notes.to_block if options[:append]
1359
+
1360
+ View.insert match
1361
+
1362
+ View.insert "\n" if line_occupied # Make room if line not blank
1363
+
1364
+ # Add line after if before heading, unless match already had one
1365
+ View.insert "\n" if Line[/^>/] && match !~ /\n$/ # If there wasn't a linebreak at the end of the match
1366
+
1367
+ line = View.line
1368
+
1369
+ View.to_highest
1370
+
1371
+ # Which case was this handling? Being in $f? Why leave cursor in $t when in $f?
1372
+ # return if path == "$t" && was_in_bar && orig.buffer != "todo.notes"
1373
+
1374
+ orig.go
1375
+
1376
+ if path == "$t" && orig.buffer == "todo.notes"
1377
+ Line.next line-1
1378
+ View.column = orig.column
1379
+ end
1380
+ end
1381
+
1382
+ def self.log
1383
+ View.open @@log
1384
+ end
1385
+
1386
+ def self.append_log dir, txt#, prefix=''
1387
+ txt = "- #{dir}\n #{txt}\n"
1388
+ File.open(@@log, "a") { |f| f << txt } rescue nil
1389
+ end
1390
+
1391
+ def self.bookmark
1392
+ match = self.stop
1393
+
1394
+ if match.nil? # If nothing searched for yet, resume search
1395
+ Search.tree_grep
1396
+ else
1397
+ Search.search_in_bookmark match
1398
+ end
1399
+ end
1400
+
1401
+ def self.searches
1402
+ begin
1403
+ $el.elvar.search_ring.to_a
1404
+ rescue Exception=>e
1405
+ ["error getting searches, probably because of special char :("]
1406
+ end
1407
+ end
1408
+
1409
+ def self.last_search
1410
+ begin
1411
+ $el.nth 0, $el.elvar.search_ring.to_a
1412
+ rescue Exception=>e
1413
+ View.beep
1414
+ return "- weird stuff in search ring!"
1415
+ end
1416
+ end
1417
+
1418
+ def self.history txt=nil
1419
+
1420
+ # If nothing selected yet, show history
1421
+
1422
+ if ! txt
1423
+ searches = self.searches.uniq
1424
+ return searches.map{|o| "| #{o}\n"}.join("")
1425
+ end
1426
+
1427
+ # Option selected, so search for it
1428
+
1429
+ txt.sub! /^\| /, ''
1430
+
1431
+ # Go back to where we came from, if we're in special search buffer
1432
+ View.kill if View.buffer_name == "@search/history/"
1433
+
1434
+ Search.isearch txt
1435
+ nil
1436
+ end
1437
+
1438
+ def self.outline_goto_once; @@outline_goto_once; end
1439
+ def self.outline_goto_once= txt; @@outline_goto_once = txt; end
1440
+
1441
+ def self.deep_outline txt, line
1442
+ txt = txt.split "\n"
1443
+ target_i = line
1444
+
1445
+ # Start with current line
1446
+
1447
+ i, children, matched_above = target_i-1, false, 1
1448
+ result = [txt[i]]
1449
+ target_indent = txt[i][/^ */].length / 2
1450
+
1451
+ # Go through each line above
1452
+
1453
+ while (i -= 1) >= 0
1454
+ # Grab lines with incrementally lower indent, but only if they have lines under!
1455
+
1456
+ line = txt[i]
1457
+ next if line.empty?
1458
+ indent = line[/^ */].length / 2
1459
+
1460
+ if indent > target_indent # If lower, skip, remembering children
1461
+ children = true
1462
+ elsif indent == target_indent # If same, only grab if there were children
1463
+ if children
1464
+ matched_above += 1
1465
+ result.unshift txt[i]
1466
+ end
1467
+ children = false
1468
+ else # Indented less
1469
+
1470
+ next if indent == 0 && line =~ /^#? ?Ol\b/ # Skip if ^Ol... line
1471
+
1472
+ matched_above += 1
1473
+ result.unshift txt[i]
1474
+ children = false
1475
+ target_indent = indent
1476
+ end
1477
+ end
1478
+
1479
+
1480
+ i, candidate = target_i-1, nil
1481
+ target_indent = txt[i][/^ */].length / 2
1482
+
1483
+ # Go through each line below
1484
+
1485
+ while (i += 1) < txt.length
1486
+ # Grab lins with incrementally lower indent, but only if they have lines under!
1487
+
1488
+ line = txt[i]
1489
+ next if line.empty?
1490
+ indent = line[/^ */].length / 2
1491
+
1492
+ if indent > target_indent # If lower, add candidate if any
1493
+ if candidate
1494
+ result << candidate
1495
+ candidate = nil
1496
+ end
1497
+
1498
+ elsif indent == target_indent # If same, only grab if there were children
1499
+ candidate = txt[i]
1500
+ else # Indented less
1501
+
1502
+ next if indent == 0 && line =~ /^#? ?Ol\b/ # Skip if ^Ol... line
1503
+
1504
+ target_indent = indent
1505
+ candidate = txt[i]
1506
+ end
1507
+
1508
+ end
1509
+
1510
+ [result.join("\n")+"\n", matched_above]
1511
+ end
1512
+
1513
+ def self.isearch_m
1514
+ match = self.stop
1515
+
1516
+ return if match # If there was a match, just stop
1517
+
1518
+ Launcher.open("- log/") if match.nil?
1519
+ end
1520
+
1521
+ def self.just_bookmark
1522
+ match = self.stop
1523
+ path = Keys.bookmark_as_path :include_file=>1 # Get path (from bookmark)
1524
+ View.open path
1525
+ View.to_highest
1526
+ Search.isearch match
1527
+ end
1528
+
1529
+ def self.enter_insert_search
1530
+ # If in file tree, do ##
1531
+ if FileTree.handles?
1532
+ Search.enter_search
1533
+ else
1534
+ Google.insert
1535
+ end
1536
+ end
1537
+
1538
+ def self.like_delete
1539
+ match = self.stop
1540
+
1541
+ line = View.line
1542
+
1543
+ View.to_highest
1544
+ $el.delete_matching_lines match
1545
+
1546
+ View.line = line
1547
+
1548
+ end
1549
+
1550
+ def self.have_right
1551
+ match = self.stop
1552
+ View.to_upper
1553
+ View.to_highest
1554
+ View << "#{match}\n\n"
1555
+ end
1556
+
1557
+ #
1558
+ # Query replaces from "1" clipboard to "2" clipboard, etc.
1559
+ #
1560
+ # Search.query_replace_nth "1", "2"
1561
+ #
1562
+ def self.query_replace_nth n1, n2
1563
+
1564
+ if Keys.up? # If up+, grab line from last diff
1565
+ a, b = DiffLog.last_intraline_diff
1566
+ return Search.query_replace a, b
1567
+ end
1568
+
1569
+ Search.query_replace Clipboard.get(n1), Clipboard.get(n2)
1570
+ end
1571
+
1572
+ end