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,48 @@
1
+ # Starting and stopping macros
2
+ class Macros
3
+
4
+ def self.menu
5
+ "
6
+ docs/
7
+ > Keys
8
+ | as+job - Start or stop recording macro
9
+ | do+job - Run macro (the last recorded one)
10
+ | up+do+job - Stop recording and apply macro to any following contiguous lines
11
+ "
12
+ end
13
+
14
+ def self.record
15
+ # If ending a macro
16
+ if $el.elvar.defining_kbd_macro
17
+ $el.end_kbd_macro nil
18
+ # If starting a macro
19
+ else
20
+ $el.start_kbd_macro nil
21
+ end
22
+ end
23
+
24
+ def self.run
25
+ # If defining a macro, just end it and run it
26
+ if $el.elvar.defining_kbd_macro
27
+ $el.end_kbd_macro nil
28
+ end
29
+
30
+ # If U prefix prefix, apply until blank line
31
+ if Keys.prefix_u?
32
+ orig = Location.new
33
+ Line.next
34
+ left = $el.point
35
+ Search.forward "^$"
36
+ $el.beginning_of_line
37
+ $el.apply_macro_to_region_lines left, $el.point
38
+ orig.go
39
+ return
40
+ elsif Keys.prefix == 0 # If 0, do to region
41
+ $el.apply_macro_to_region_lines View.range_left, View.range_right
42
+ return
43
+ end
44
+
45
+ # Run it prefix times
46
+ $el.call_last_kbd_macro $el.elvar.current_prefix_arg || 1
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ class Man
2
+ def self.menu command=nil
3
+ if command == nil
4
+ return "
5
+ | Type a command to show its man page:
6
+ - example: ls
7
+ - last used: @last/man/
8
+ "
9
+ end
10
+
11
+ `man #{command} | col -x -b`.gsub(/^/, '| ').gsub(/^\| $/, '|')
12
+
13
+ end
14
+
15
+ def self.root
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,708 @@
1
+ class Menu
2
+
3
+ def self.menu
4
+ '
5
+ - history/
6
+ - @log/
7
+ - @last/
8
+ - @all/
9
+ - .create/
10
+ - here/
11
+ - class/
12
+ - .install/
13
+ - gem/
14
+ - .setup/
15
+ - @~/menus/
16
+ - .reload_menus/
17
+ - .api/
18
+ > Summary
19
+ | How to use ruby code to define menus.
20
+ |
21
+ | You can create sophisticated menus backed by classes, or by using other
22
+ | simple means:
23
+ - .classes/
24
+ - .simple class/
25
+ - .menu with method/
26
+ - .menu with two methods/
27
+ - other/
28
+ - With a string/
29
+ |
30
+ | Menu.fish :menu=>"- salmon/\n- tuna/\n - yellow fin/"
31
+ |
32
+ Try it out by typing 1 do_ruby (C-1 Ctrl-d Ctrl-r) while on it, then
33
+ double-clicking on this menu to see what happens:
34
+ |
35
+ @fish/
36
+ |
37
+ - Delegating to an existing menu/
38
+ |
39
+ | Menu.critters :menu=>"foo/animals"
40
+ |
41
+ @critters/
42
+ |
43
+ - Using a block/
44
+ |
45
+ | Menu.foo do
46
+ | "hey/"
47
+ | end
48
+ |
49
+ The block can optionally take a |path| param to handle multiple levels
50
+ of nesting.
51
+ |
52
+ | Menu.foo do |path|
53
+ | "hey/#{path}"
54
+ | end
55
+ |
56
+ - Extract menu text from somewhere/
57
+ | Tree.children just expects text that is in the form of a menu (lines with
58
+ | 2-space indenting for nesting). So, the text can be pulled from
59
+ | anywhere, such as a part of a larger file:
60
+ |
61
+ | Menu.lawn do |path|
62
+ | menu = Notes.read_block("/tmp/garage.notes", "> Lawn")
63
+ | Tree.children menu, Tree.rootless(path)
64
+ | end
65
+ |
66
+ |
67
+ | If you want to create a very simple menu you can do so without code,
68
+ | by just putting the menu in a file such as ~/menu/foo.menu. See:
69
+ |
70
+ << docs/how_to_create/
71
+ - .docs/
72
+ - .How to use/
73
+ - .How to create/
74
+ - .keys/
75
+ > Summary
76
+ | Helpful keyboard shortcuts when using menus.
77
+ |
78
+ | - as+menu
79
+ | - Save changes to menu (or create new one)
80
+ | - to+menu
81
+ | - Jump to file that implements menu
82
+ |
83
+ '
84
+ end
85
+
86
+ def self.install *args
87
+ Xiki.dont_search
88
+ Tree.quote "
89
+ > TODO
90
+ - implement this.
91
+
92
+ - Should it look for installed gems with this name?
93
+ - Should it just show commands to do a gem install?
94
+ - How would it know whether it the gem has a xiki menu?
95
+ "
96
+ end
97
+
98
+ def self.create *args
99
+ type = args[0]
100
+
101
+ return self.create_here if type == "here"
102
+ return self.create_class if type == "class"
103
+ return self.create_more(*args.drop(1)) if type == "more"
104
+
105
+ "- unknown option #{type} passed to .create!"
106
+ end
107
+
108
+ def self.create_here
109
+
110
+ # TODO: Handle various use cases
111
+ # "menu/create/here/" at left margin
112
+ # "@menu/create/here/" nested
113
+ # "menu/create/\n here/" at left margin
114
+ # "@menu/create/\n here/" nested
115
+
116
+ trunk = Xiki.trunk
117
+ if wrapper = trunk[-2] # If @menu/create/here is nested
118
+ menu = Tree.root wrapper
119
+ else # If put it under a fake menu
120
+
121
+ # What? This is if it's not nested? - is this used?
122
+
123
+ # TODO: Go to left margin and remove menu...
124
+
125
+ Tree.to_root
126
+
127
+ Tree.kill_under
128
+ menu = "foo"
129
+ Line.sub! /([ +-]*).*/, "\\1#{menu}/"
130
+ # Insert it wherever we are
131
+ end
132
+ Xiki.dont_search
133
+
134
+ name_text = menu == "foo" ?
135
+ "and change '#{menu}' to something" :
136
+ "to go under the '#{menu}' menu"
137
+
138
+ snake = TextUtil.snake_case menu
139
+
140
+ Tree << "
141
+ | Supply a few items here. Then do as+menu (type Ctrl-a Ctrl-m) to create
142
+ | the '#{menu}' menu. Or, just create '~/menus/#{snake}.menu' yourself.
143
+ - example item/
144
+ - another/
145
+ - and another/
146
+ "
147
+
148
+ nil
149
+
150
+ end
151
+
152
+ def self.create_class
153
+ trunk = Xiki.trunk
154
+ if wrapper = trunk[-2]
155
+ # Just do in-line
156
+ menu = TextUtil.snake_case Tree.root(wrapper)
157
+ else
158
+ menu = 'foo'
159
+ end
160
+
161
+ Xiki.dont_search
162
+
163
+ Tree << %`
164
+ | Update this sample class to your liking. Then do as+update (type
165
+ | Ctrl-a, Ctrl-u) to create the '#{menu}' class file.
166
+ - @~/menus/
167
+ - #{menu}.rb
168
+ | class #{TextUtil.camel_case(menu)}
169
+ | def self.menu *args
170
+ | "- Args Passed: \#{args.inspect}\\n- Customize me in) @ ~/menus/#{menu}.rb"
171
+ | end
172
+ | end
173
+ - more examples) @menu/api/classes/
174
+ `
175
+ nil
176
+ end
177
+
178
+ def self.simple_class *args
179
+ root = 'foo'
180
+ trunk = Xiki.trunk
181
+ root = TextUtil.snake_case(trunk[-2][/^[\w -]+/]) if trunk.length > 1 # If nested path (due to @), grab root of parent
182
+
183
+ %`
184
+ - @~/menus/
185
+ - #{root}.rb
186
+ | class #{TextUtil.camel_case(root)}
187
+ | def self.menu *args
188
+ | "- args passed: \#{args.inspect}\n- Customize me in) @ ~/menus/#{menu}.rb"
189
+ | end
190
+ | end
191
+ `
192
+ end
193
+
194
+ def self.menu_with_method *args
195
+ root = 'foo'
196
+ trunk = Xiki.trunk
197
+ root = TextUtil.snake_case(trunk[-2][/^[\w -]+/]) if trunk.length > 1 # If nested path (due to @), grab root of parent
198
+
199
+ %`
200
+ - @~/menus/
201
+ - #{root}.rb
202
+ | class #{TextUtil.camel_case(root)}
203
+ | def self.menu
204
+ | "
205
+ | - cake/
206
+ | - chocolate/
207
+ | - .pie/
208
+ | "
209
+ | end
210
+ |
211
+ | def self.pie
212
+ | "- apple/"
213
+ | end
214
+ | end
215
+ `
216
+ end
217
+
218
+ def self.menu_with_two_methods *args
219
+ root = 'foo'
220
+ trunk = Xiki.trunk
221
+ root = TextUtil.snake_case(trunk[-2][/^[\w -]+/]) if trunk.length > 1 # If nested path (due to @), grab root of parent
222
+
223
+ %`
224
+ - @~/menus/
225
+ - #{root}.rb
226
+ | class #{TextUtil.camel_case(root)}
227
+ | def self.menu
228
+ | "
229
+ | - sammiches/
230
+ | - ham/
231
+ | - .buy/
232
+ | - tofu/
233
+ | - .buy/
234
+ | - .checkout/
235
+ | - cash/
236
+ | - credit/
237
+ | "
238
+ | end
239
+ | def self.buy category, item
240
+ | "- buying \#{item} \#{category}"
241
+ | end
242
+ | def self.checkout kind
243
+ | "- checking out as \#{kind}..."
244
+ | end
245
+ | end
246
+ |
247
+ `
248
+ end
249
+
250
+ def self.how_to_use *args
251
+ %`
252
+ > Summary
253
+ | How to use Xiki menus. Note this refers to the wiki-style menus, not the menu bar.
254
+ |
255
+ | All menus can be used the same way. Just type something and double-click
256
+ | on it (or type Ctrl-enter while the cursor is on the line).
257
+ |
258
+ - example/
259
+ | 1: type "foo" on a line (the "@" isn't necessary when the line isn't indented)
260
+ @ foo
261
+ |
262
+ | 2: double-click on it to drill in. You can try it on the line above. It will look like this:
263
+ @ foo/
264
+ | - sammiches/
265
+ | - dranks/
266
+ |
267
+ | 3: double-click to drill in further. It will look like this:
268
+ @ foo/
269
+ | - sammiches/
270
+ | - ham/
271
+ | - tofu/
272
+ | - dranks/
273
+ |
274
+ - using the mouse/
275
+ | You can click on the "bullets" (the - and + at the beginnings of lines)
276
+ | to expand and collapse. You can also double-click to expand and
277
+ | collapse.
278
+ |
279
+ - search to narrow down/
280
+ | When you double-click a line the cursor turns blue and you can type
281
+ | letters to search and narrow down the list.
282
+ |
283
+ - misc keys/
284
+ | - Return: stops searching and launches (expands file or dir)
285
+ | - Tab: like return but hides others
286
+ | - ;: like return but collapses path
287
+ |
288
+ | - C-g: stops searching
289
+ |
290
+ | - Arrow keys: you can use them to go up and down and expand and collapse
291
+ |
292
+ `
293
+ end
294
+
295
+ def self.how_to_create *args
296
+ txt = %q`
297
+ > Summary
298
+ | How to make your own menus in Xiki. Note this refers to wiki-style
299
+ | menus (such as this one), not the menu bar.
300
+ |
301
+ - Creating .menu files/
302
+ | You can make menus without code, by just put "whatever.menu" files in the
303
+ | "menu/" dir in your home dir.
304
+ |
305
+ | For example you could create a "foo.menu" file with the contents
306
+ | "- sammiches/..." etc:
307
+ |
308
+ - TODO: get these to expand out somehow! - maybe pass another arg to Tree.children below? - probably bad idea
309
+ - ~/menus/
310
+ - foo.menu
311
+ | - sammiches/
312
+ | - ham/
313
+ | - tofu/
314
+ | - dranks/
315
+ | - foty/
316
+ |
317
+ - Delegating/
318
+ | This makes a foo/ menu that you can expand. Even though these menus
319
+ | don't run code themselves, they can delegate to other menus or run code,
320
+ | like:
321
+ |
322
+ - ~/menus/
323
+ - foo.menu
324
+ | - @mymenu/
325
+ | - @MyClass.my_method
326
+ |
327
+ `
328
+
329
+ Tree.children(txt, args.join('/'))
330
+ end
331
+
332
+ def self.reload_menus
333
+ Launcher.reload_menu_dirs
334
+ View.flash
335
+ nil
336
+ end
337
+
338
+ def self.[] path
339
+ path, rest = path.split '/', 2
340
+
341
+ self.call path, rest
342
+ end
343
+
344
+ def self.call root, rest=nil
345
+ menus = Launcher.menus
346
+ block = menus[0][root] || menus[1][root]
347
+ return if block.nil?
348
+ Tree.output_and_search block, :line=>"#{root}/#{rest}", :just_return=>1
349
+ end
350
+
351
+ def self.method_missing *args, &block
352
+ Launcher.method_missing *args, &block
353
+ "- defined!"
354
+ end
355
+
356
+ def self.split path, options={}
357
+ path = path.sub /\/$/, ''
358
+ path = Tree.rootless path if options[:rootless]
359
+
360
+ return [] if path.empty?
361
+
362
+ groups = path.split '/|', -1
363
+
364
+ result = groups[0] =~ /^\|/ ?
365
+ [groups[0]] :
366
+ groups[0].split('/', -1)
367
+
368
+ result += groups[1..-1].map{|o| "|#{o}"}
369
+ end
370
+
371
+ def self.to_menu
372
+ # Take best guess, by looking through dirs for root
373
+ trunk = Xiki.trunk
374
+
375
+ return View.<<("- You weren't on a menu\n | To jump to a menu's implementation, put your cursor on it\n | (or type it on a blank line) and then do as+menu (ctrl-a ctrl-m)\n | Or, look in one of these dirs:\n - ~/menus/\n - $xiki/menus/") if trunk[-1].blank?
376
+
377
+ root = trunk[0][/^[\w _-]+/]
378
+
379
+ root = trunk[-1][/^[\w _-]+/] if ! Keys.prefix_u
380
+
381
+ root.gsub!(/[ -]/, '_') if root
382
+
383
+ root.downcase!
384
+
385
+ (["#{Xiki.dir}lib/"]+Launcher::MENU_DIRS).reverse.each do |dir|
386
+ next unless File.directory? dir
387
+ file = Dir["#{dir}/#{root}.*"]
388
+ next unless file.any?
389
+ return View.open file[0]
390
+ end
391
+
392
+ # message = "
393
+ # - No menu found:
394
+ # | No \"#{root}\" menu or class file found in these dirs:
395
+ # @ ~/menus/
396
+ # @ $x/menus/
397
+ # ".unindent
398
+
399
+ # Should be able to get it right from proc
400
+
401
+ proc = Launcher.menus[1][root]
402
+
403
+ return View.flash "- Menu 'root' doesn't exist!", :times=>4 if ! proc
404
+
405
+ location = proc.source_location # ["./firefox.rb", 739]
406
+ location[0].sub! /^\.\//, Xiki.dir
407
+ View.open location[0]
408
+ View.line = location[1]
409
+
410
+ end
411
+
412
+ def self.external menu, options={}
413
+
414
+ View.message ""
415
+
416
+ View.wrap :off
417
+
418
+ # IF nothing passed, must want to do tiny search box
419
+ if menu.empty?
420
+ Launcher.open ""
421
+ View.message ""
422
+ View.prompt "Type anything", :timed=>1, :times=>2 #, :color=>:rainbow
423
+
424
+ Launcher.launch
425
+ else
426
+ Launcher.open menu, options
427
+ end
428
+ end
429
+
430
+ def self.as_menu
431
+ orig = View.cursor
432
+
433
+ Tree.to_root
434
+
435
+ root, left = Line.value, View.cursor
436
+ root = Line.without_label :line=>root
437
+
438
+ root = TextUtil.snake_case(root).sub(/^_+/, '')
439
+
440
+ if Line.value(2) =~ /^ +\| Supply a few items here/ # If sample text, remove
441
+ Line.next
442
+ while Line.=~(/^ +\| /)
443
+ Line.delete
444
+ end
445
+ Line.previous
446
+ orig = nil
447
+ end
448
+
449
+ Tree.after_children
450
+ right = View.cursor
451
+ View.cursor = left
452
+
453
+ # Go until end of paragraph (simple for now)
454
+ Effects.blink :left=>left, :right=>right
455
+ txt = View.txt left, right
456
+ txt.sub! /.+\n/, ''
457
+ txt.gsub! /^ /, ''
458
+ txt.unindent
459
+
460
+ return Tree << "| You must supply something to put under the '#{root}' menu.\n| First, add some lines here, such as these:\n- line/\n- another line/\n" if txt.empty?
461
+
462
+ path = File.expand_path "~/menus/#{root}.menu"
463
+
464
+ file_existed = File.exists? path
465
+
466
+ if file_existed
467
+ treeb = File.read path
468
+ txt = Tree.restore txt, treeb
469
+
470
+ DiffLog.save_diffs :patha=>path, :textb=>txt
471
+ end
472
+
473
+ File.open(path, "w") { |f| f << txt }
474
+
475
+ View.cursor = orig if orig
476
+
477
+ require_menu path
478
+
479
+ View.flash "- #{file_existed ? 'Updated' : 'Created'} ~/menus/#{root}.menu", :times=>3
480
+ nil
481
+ end
482
+
483
+ @@loaded_already = {}
484
+
485
+ def self.load_if_changed file
486
+ return :not_found if ! File.exists?(file)
487
+ previous = @@loaded_already[file]
488
+ recent = File.mtime(file)
489
+
490
+ if previous == nil
491
+ # require file
492
+ load file
493
+ @@loaded_already[file] = recent
494
+ return
495
+ end
496
+
497
+ return if recent <= previous
498
+
499
+ load file
500
+ @@loaded_already[file] = recent
501
+ end
502
+
503
+ def self.collapser_launcher
504
+
505
+ line = Line.value
506
+ arrows = line[/<+/].length
507
+ arrows -= 1 if arrows > 1 # Make "<<" go back just 1, etc.
508
+
509
+ # line.sub! /(^ +)= /, "\\1< " # Temporarily get "=" to work too
510
+ line = Line.without_label :line=>line
511
+
512
+ skip = line.empty? && arrows - 1
513
+
514
+ Line.sub! /^( +)<+ .+/, "\\1- " # Delete after bullet to prepare for loop
515
+
516
+ arrows.times do |i|
517
+
518
+ # If no items left on current line, jump to parent and delete
519
+ if Line =~ /^[ +-]+$/
520
+ Tree.to_parent
521
+ Tree.kill_under
522
+ Move.to_end
523
+ end
524
+
525
+ unless i == skip # Remove last item, or after bullet if no items
526
+ Line.sub!(/\/[^\/]+\/$/, '/') || Line.sub!(/^([ @+-]*).*/, "\\1")
527
+ end
528
+ end
529
+
530
+ if Line.indent.blank?
531
+ line.sub! /^@ ?/, ''
532
+ Line.sub! /^@ ?/, ''
533
+ end
534
+
535
+ Line << line unless skip
536
+ Launcher.launch
537
+
538
+ end
539
+
540
+ def self.root_collapser_launcher
541
+
542
+ View.cursor
543
+
544
+
545
+ # Grab line
546
+ line = Line.value
547
+
548
+ arrows = line[/<+/].length
549
+
550
+ line.sub!(/ *<+@ /, '')
551
+
552
+ # Go up to root, and kill under
553
+ arrows.times { Tree.to_root }
554
+ Tree.kill_under
555
+
556
+ # Insert line, and launch
557
+ old = Line.delete :leave_linebreak
558
+ old.sub! /^( *).+/, "\\1"
559
+ old << "@" if old =~ /^ / # If any indent, @ is needed
560
+ View << "#{old}#{line}"
561
+
562
+ Launcher.launch
563
+ end
564
+
565
+ def self.replacer_launcher
566
+ Line.sub! /^( +)<+= /, "\\1+ "
567
+
568
+ # Run in place, grab output, then move higher and show output
569
+
570
+ orig = View.line
571
+ Launcher.launch :no_search=>1
572
+
573
+ # If didn't move line, assume it had no output, and it's collapse things itself
574
+ return if orig == View.line
575
+
576
+ # If it inserted something
577
+
578
+ output = Tree.siblings :everything=>1
579
+
580
+ # return
581
+
582
+ # Shouldn't this be looping like self.collapser_launcher ?
583
+ Tree.to_parent
584
+ Tree.to_parent
585
+ Tree.kill_under :no_plus=>1
586
+ Tree << output
587
+
588
+ # TODO: do search now, after insterted?
589
+
590
+ end
591
+
592
+ def self.menu_to_hash txt
593
+ txt = File.read txt if txt =~ /\A\/.+\z/ # If 1 line and starts with slash, read file
594
+
595
+ txt.gsub(/^\| /, '').split("\n").inject({}) do |o, txt|
596
+ txt = txt.split(/ : /)
597
+ o[txt[0]] = txt[1]
598
+ o
599
+ end
600
+
601
+ end
602
+
603
+ # def self.config txt, *args
604
+
605
+ # # TODO: implement
606
+ # # Args look like sample invocation below
607
+ # # If not there, create it first, using supplied default
608
+ # # Insert quoted file contents to be edited
609
+
610
+ # # Sample invocation
611
+ # # Menu.config "
612
+ # # - @ ~/xiki_config/browser.notes
613
+ # # | - default browser:
614
+ # # | - Firefox
615
+ # # | - others:
616
+ # # | - Safari
617
+ # # | - Chrome
618
+ # # ", *args
619
+
620
+ # "TODO"
621
+ # end
622
+
623
+ # Moves item to root of tree (replacing tree), then launches.
624
+ def self.do_as_menu
625
+ line = Line.value
626
+
627
+ # If on ^@... line and there's child on next line...
628
+
629
+ on_subtree = line =~ /^[ +-]*@/ && Tree.has_child?
630
+
631
+ txt = on_subtree ? Tree.subtree.unindent.sub(/^[ @+-]+/, '') : Tree.path.last
632
+
633
+ Keys.prefix_u ? Tree.to_root(:highest=>1) : Tree.to_root
634
+ Tree.kill_under
635
+
636
+ Line.sub! /^([ @]*).+/, "\\1#{txt}"
637
+
638
+ return if on_subtree
639
+
640
+ # replace line with menu
641
+
642
+ Launcher.launch
643
+ end
644
+
645
+
646
+ # The following 3 methods are for the menu bar
647
+ # - a different use of the "Menu" class
648
+ # TODO move them into menu_bar.rb ?
649
+
650
+ def self.add_menu *name
651
+ menu_spaces = name.join(' ').downcase
652
+ menu_dashes = name.join('-').downcase
653
+ name = name[-1]
654
+
655
+ lisp = %Q<
656
+ (define-key global-map
657
+ [menu-bar #{menu_spaces}]
658
+ (cons "#{name}" (make-sparse-keymap "#{menu_dashes}")))
659
+ >
660
+ $el.el4r_lisp_eval lisp
661
+
662
+ menu = $el.elvar.menu_bar_final_items.to_a
663
+ $el.elvar.menu_bar_final_items = menu.push(name.downcase.to_sym)
664
+ end
665
+
666
+ def self.add_item menu, name, function
667
+
668
+ menu_spaces = menu.join(' ').downcase
669
+ lisp = "
670
+ (define-key global-map
671
+ [menu-bar #{menu_spaces} #{function}]
672
+ '(\"#{name}\" . #{function}))
673
+ "
674
+ $el.el4r_lisp_eval lisp
675
+ end
676
+
677
+ ROOT_MENU = 'Keys'
678
+
679
+ def self.init
680
+
681
+ return if ! $el
682
+
683
+ Mode.define(:menu, ".menu") do
684
+ Notes.mode
685
+ end
686
+
687
+ add_menu ROOT_MENU
688
+
689
+ menus = [
690
+ [ROOT_MENU, 'To'],
691
+ [ROOT_MENU, 'Open'],
692
+ [ROOT_MENU, 'Layout'],
693
+ [ROOT_MENU, 'As'],
694
+ [ROOT_MENU, 'Enter'],
695
+ [ROOT_MENU, 'Do'],
696
+ [ROOT_MENU, 'Search']
697
+ ]
698
+ menus.reverse.each do |tuple|
699
+ add_menu tuple[0], tuple[1]
700
+ end
701
+ end
702
+
703
+
704
+ end
705
+
706
+ Menu.init # Define mode
707
+
708
+