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.
- data/Gemfile +11 -0
- data/LICENSE +22 -0
- data/README.markdown +83 -0
- data/Rakefile +8 -0
- data/bin/xiki +46 -0
- data/etc/command/xiki_command.rb +203 -0
- data/etc/command/xiki_process.rb +52 -0
- data/etc/command/xiki_wrapper +2 -0
- data/etc/js/menu1.js +55 -0
- data/etc/js/xiki.js +259 -0
- data/etc/logo.png +0 -0
- data/etc/presentations/bootstrap.deck +5 -0
- data/etc/presentations/databases.deck +41 -0
- data/etc/presentations/diffs.deck +23 -0
- data/etc/presentations/documentation.deck +14 -0
- data/etc/presentations/effects.deck +5 -0
- data/etc/presentations/face.deck +297 -0
- data/etc/presentations/files.deck +79 -0
- data/etc/presentations/icons.deck +22 -0
- data/etc/presentations/images.deck +24 -0
- data/etc/presentations/key_shortcuts.deck +16 -0
- data/etc/presentations/macros.deck +18 -0
- data/etc/presentations/menu_classes.deck +44 -0
- data/etc/presentations/menu_directories.deck +30 -0
- data/etc/presentations/notes.deck +19 -0
- data/etc/presentations/other_languages.deck +55 -0
- data/etc/presentations/other_wiki_syntaxes.deck +4 -0
- data/etc/presentations/piano.deck +5 -0
- data/etc/presentations/potential/diffs.deck +38 -0
- data/etc/presentations/potential/evolution.deck +18 -0
- data/etc/presentations/potential/intro.deck +711 -0
- data/etc/presentations/potential/intro1.deck +711 -0
- data/etc/presentations/potential/intro2.deck +97 -0
- data/etc/presentations/potential/make_mysql_menu.deck +36 -0
- data/etc/presentations/potential/ruby_development.deck +17 -0
- data/etc/presentations/potential/ui_prototyping.deck +50 -0
- data/etc/presentations/potential/web_dev.deck +4 -0
- data/etc/presentations/potential/web_development.deck +10 -0
- data/etc/presentations/potential/wiki.deck +45 -0
- data/etc/presentations/presentations.deck +24 -0
- data/etc/presentations/rails_development.deck +29 -0
- data/etc/presentations/search_key_shortcuts.deck +37 -0
- data/etc/presentations/simplest_possible_ui.deck +37 -0
- data/etc/presentations/svg.deck +5 -0
- data/etc/presentations/testing.deck +28 -0
- data/etc/presentations/the_end.deck +13 -0
- data/etc/presentations/type_something_and_double_click.deck +57 -0
- data/etc/presentations/type_the_acronym.deck +144 -0
- data/etc/presentations/web_browser.deck +56 -0
- data/etc/presentations/xiki_command.deck +20 -0
- data/etc/presentations/xiki_url.deck +14 -0
- data/etc/shark.icns +0 -0
- data/etc/shark_script.icns +0 -0
- data/etc/snippets/html.notes +7 -0
- data/etc/snippets/notes.notes +20 -0
- data/etc/snippets/rb.notes +38 -0
- data/etc/templates/menu_template.menu +2 -0
- data/etc/templates/menu_template.rb +8 -0
- data/etc/templates/template.rb +5 -0
- data/etc/themes/Dark_Metal.notes +28 -0
- data/etc/themes/Orange_Path.notes +15 -0
- data/etc/themes/Shiny_Blue.notes +27 -0
- data/etc/themes/Shiny_Green.notes +27 -0
- data/etc/wrappers/wrapper.js +17 -0
- data/etc/wrappers/wrapper.py +20 -0
- data/etc/wrappers/wrapper.rb +25 -0
- data/lib/block.rb +72 -0
- data/lib/bookmarks.rb +352 -0
- data/lib/buffers.rb +170 -0
- data/lib/clipboard.rb +333 -0
- data/lib/code.rb +860 -0
- data/lib/code_tree.rb +476 -0
- data/lib/color.rb +274 -0
- data/lib/console.rb +557 -0
- data/lib/control_lock.rb +9 -0
- data/lib/control_tab.rb +176 -0
- data/lib/core_ext.rb +31 -0
- data/lib/cursor.rb +111 -0
- data/lib/deletes.rb +65 -0
- data/lib/diff_log.rb +297 -0
- data/lib/effects.rb +145 -0
- data/lib/environment.rb +5 -0
- data/lib/file_tree.rb +1875 -0
- data/lib/files.rb +334 -0
- data/lib/hide.rb +259 -0
- data/lib/history.rb +286 -0
- data/lib/image.rb +51 -0
- data/lib/incrementer.rb +15 -0
- data/lib/insert.rb +7 -0
- data/lib/irc.rb +22 -0
- data/lib/key_bindings.rb +658 -0
- data/lib/keys.rb +754 -0
- data/lib/launcher.rb +1351 -0
- data/lib/line.rb +429 -0
- data/lib/links.rb +6 -0
- data/lib/location.rb +175 -0
- data/lib/macros.rb +48 -0
- data/lib/man.rb +19 -0
- data/lib/menu.rb +708 -0
- data/lib/merb.rb +259 -0
- data/lib/message.rb +5 -0
- data/lib/meths.rb +56 -0
- data/lib/mode.rb +34 -0
- data/lib/move.rb +248 -0
- data/lib/notes.rb +1000 -0
- data/lib/numbers.rb +45 -0
- data/lib/ol.rb +203 -0
- data/lib/ol_helper.rb +44 -0
- data/lib/overlay.rb +167 -0
- data/lib/pause_means_space.rb +68 -0
- data/lib/php.rb +22 -0
- data/lib/projects.rb +21 -0
- data/lib/relinquish_exception.rb +2 -0
- data/lib/remote.rb +206 -0
- data/lib/requirer.rb +46 -0
- data/lib/rest_tree.rb +108 -0
- data/lib/ruby.rb +57 -0
- data/lib/ruby_console.rb +165 -0
- data/lib/search.rb +1572 -0
- data/lib/search_term.rb +40 -0
- data/lib/snippet.rb +68 -0
- data/lib/specs.rb +229 -0
- data/lib/styles.rb +274 -0
- data/lib/svn.rb +682 -0
- data/lib/text_util.rb +110 -0
- data/lib/tree.rb +1871 -0
- data/lib/tree_cursor.rb +87 -0
- data/lib/trouble_shooting.rb +27 -0
- data/lib/url_tree.rb +11 -0
- data/lib/view.rb +1474 -0
- data/lib/window.rb +133 -0
- data/lib/xiki.rb +404 -0
- data/menus/accounts.rb +5 -0
- data/menus/address_book.rb +21 -0
- data/menus/agenda.rb +28 -0
- data/menus/all.rb +5 -0
- data/menus/amazon.rb +16 -0
- data/menus/app.rb +16 -0
- data/menus/applescript.rb +46 -0
- data/menus/as.rb +15 -0
- data/menus/bookmarklet.rb +63 -0
- data/menus/bootstrap.rb +568 -0
- data/menus/browse.rb +13 -0
- data/menus/browser.rb +78 -0
- data/menus/cassandra_db.rb +36 -0
- data/menus/chmod.rb +27 -0
- data/menus/classes.rb +5 -0
- data/menus/coffee_script.rb +35 -0
- data/menus/computer.rb +24 -0
- data/menus/contacts.rb +5 -0
- data/menus/cookies.rb +25 -0
- data/menus/couch.rb +184 -0
- data/menus/crop.rb +45 -0
- data/menus/css.rb +55 -0
- data/menus/current.rb +5 -0
- data/menus/db.rb +12 -0
- data/menus/deck.rb +219 -0
- data/menus/dictionary.rb +9 -0
- data/menus/dir.rb +8 -0
- data/menus/disk.rb +5 -0
- data/menus/do.rb +13 -0
- data/menus/docs.rb +58 -0
- data/menus/dotsies.rb +107 -0
- data/menus/edited.rb +18 -0
- data/menus/emacs.rb +17 -0
- data/menus/enter.rb +13 -0
- data/menus/eval.rb +17 -0
- data/menus/executable.rb +16 -0
- data/menus/filter.rb +46 -0
- data/menus/firefox.rb +607 -0
- data/menus/foo.rb +30 -0
- data/menus/french.rb +7 -0
- data/menus/git.rb +185 -0
- data/menus/gito.rb +785 -0
- data/menus/google.rb +35 -0
- data/menus/google_images.rb +11 -0
- data/menus/google_patents.rb +10 -0
- data/menus/gutenberg.rb +13 -0
- data/menus/head.rb +10 -0
- data/menus/headings.rb +39 -0
- data/menus/html.rb +61 -0
- data/menus/icon.rb +40 -0
- data/menus/images.menu +2 -0
- data/menus/img.rb +15 -0
- data/menus/info.rb +9 -0
- data/menus/ip.rb +10 -0
- data/menus/iterm.rb +36 -0
- data/menus/itunes.rb +78 -0
- data/menus/javascript.rb +74 -0
- data/menus/layout.rb +18 -0
- data/menus/local_storage.rb +67 -0
- data/menus/ls.rb +19 -0
- data/menus/mac.rb +87 -0
- data/menus/maps.rb +18 -0
- data/menus/matches.rb +18 -0
- data/menus/memcache.rb +117 -0
- data/menus/mkdir.rb +23 -0
- data/menus/mongo.rb +83 -0
- data/menus/mysql.rb +294 -0
- data/menus/node.rb +88 -0
- data/menus/open.rb +19 -0
- data/menus/outline.rb +24 -0
- data/menus/piano.rb +746 -0
- data/menus/postgres.rb +34 -0
- data/menus/pre.rb +5 -0
- data/menus/python.rb +39 -0
- data/menus/rails.rb +160 -0
- data/menus/rake.rb +12 -0
- data/menus/redmine.rb +168 -0
- data/menus/riak_tree.rb +204 -0
- data/menus/rss.rb +15 -0
- data/menus/safari.rb +11 -0
- data/menus/sass.rb +15 -0
- data/menus/say.rb +6 -0
- data/menus/scale.rb +49 -0
- data/menus/serve.rb +78 -0
- data/menus/shuffle.rb +24 -0
- data/menus/spanish.rb +7 -0
- data/menus/standalone.rb +57 -0
- data/menus/tail.rb +41 -0
- data/menus/technologies.rb +19 -0
- data/menus/themes.rb +32 -0
- data/menus/thesaurus.rb +13 -0
- data/menus/to.rb +24 -0
- data/menus/twitter.rb +57 -0
- data/menus/wikipedia.rb +34 -0
- data/menus/words.rb +11 -0
- data/spec/code_tree_spec.rb +59 -0
- data/spec/diff_log_spec.rb +40 -0
- data/spec/file_tree_spec.rb +102 -0
- data/spec/keys_spec.rb +24 -0
- data/spec/line_spec.rb +68 -0
- data/spec/menu_spec.rb +50 -0
- data/spec/ol_spec.rb +98 -0
- data/spec/remote_spec.rb +43 -0
- data/spec/search_spec.rb +162 -0
- data/spec/text_util_spec.rb +119 -0
- data/spec/tree_cursor_spec.rb +91 -0
- data/spec/tree_spec.rb +955 -0
- data/tests/console_test.rb +11 -0
- data/tests/couch_db_test.rb +12 -0
- data/tests/diff_log_test.rb +43 -0
- data/tests/el_mixin.rb +16 -0
- data/tests/git_test.rb +95 -0
- data/tests/keys_test.rb +19 -0
- data/tests/line_test.rb +38 -0
- data/tests/merb_test.rb +11 -0
- data/tests/redmine_test.rb +50 -0
- data/tests/remote_test.rb +31 -0
- data/tests/rest_tree_test.rb +70 -0
- data/xiki.gemspec +37 -0
- metadata +332 -0
data/lib/launcher.rb
ADDED
|
@@ -0,0 +1,1351 @@
|
|
|
1
|
+
require 'effects'
|
|
2
|
+
require 'requirer'
|
|
3
|
+
|
|
4
|
+
require 'xiki'
|
|
5
|
+
|
|
6
|
+
Requirer.require_gem 'activesupport', :name2=>'active_support/ordered_hash'
|
|
7
|
+
Requirer.require_gem 'httparty', :optional=>1 # Not super-important
|
|
8
|
+
Requirer.require_gem 'haml', :optional=>1
|
|
9
|
+
|
|
10
|
+
class Launcher
|
|
11
|
+
|
|
12
|
+
CLEAR_CONSOLES = [
|
|
13
|
+
"*ol",
|
|
14
|
+
"*output - tail of /tmp/ds_ol.notes",
|
|
15
|
+
"*visits - tail of /tmp/visit_log.notes",
|
|
16
|
+
"*console app",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
MENU_DIRS = [
|
|
20
|
+
"#{Xiki.dir}menus",
|
|
21
|
+
File.expand_path("~/menus"),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
@@log = File.expand_path("~/.emacs.d/menu_log.notes")
|
|
25
|
+
|
|
26
|
+
# Use @launcher/options/show or launch/ to enable.
|
|
27
|
+
# Look in /tmp/output.notes
|
|
28
|
+
@@just_show = false
|
|
29
|
+
|
|
30
|
+
@@launchers ||= ActiveSupport::OrderedHash.new
|
|
31
|
+
@@launchers_procs ||= []
|
|
32
|
+
@@launchers_parens ||= {}
|
|
33
|
+
@@menus ||= [{}, {}] # [.menu files, .rb files]
|
|
34
|
+
|
|
35
|
+
def self.menus
|
|
36
|
+
@@menus
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.menu_keys
|
|
40
|
+
(@@menus[0].keys + @@menus[1].keys).sort.uniq #.select do |possibility|
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.menu
|
|
44
|
+
%`
|
|
45
|
+
- .setup/
|
|
46
|
+
> Toggle Temporarily just showing the launcher that matched
|
|
47
|
+
- .show or launch/
|
|
48
|
+
- docs/
|
|
49
|
+
> Summary
|
|
50
|
+
Launcher is the class that handles "launching" things (double-clicking on a
|
|
51
|
+
line, or typing Ctrl-enter).
|
|
52
|
+
|
|
53
|
+
> See
|
|
54
|
+
@launcher/api/
|
|
55
|
+
- api/
|
|
56
|
+
> Open menu in new buffer
|
|
57
|
+
@ Launcher.open "computer"
|
|
58
|
+
|
|
59
|
+
> Insert monu
|
|
60
|
+
@ Launcher.insert "computer" # Assumes you're on a blank line
|
|
61
|
+
|
|
62
|
+
> Invoke (used behind the scenes?)
|
|
63
|
+
@ p Launcher.invoke 'Computer', 'computer/ip/'
|
|
64
|
+
`
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.show_or_launch
|
|
68
|
+
@@just_show = ! @@just_show
|
|
69
|
+
View.flash "- Will #{@@just_show ? 'just show' : 'actually launch'}!"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.last path=nil, options={}
|
|
73
|
+
path = path.sub /^last\/?/, '' if path
|
|
74
|
+
|
|
75
|
+
paths = IO.readlines self.log_file
|
|
76
|
+
|
|
77
|
+
# If nothing passed, just list all roots
|
|
78
|
+
|
|
79
|
+
if path.blank?
|
|
80
|
+
paths.map!{|o| o.sub /\/.+/, '/'} # Cut off after path
|
|
81
|
+
paths = paths.reverse.uniq
|
|
82
|
+
paths.delete "- #{options[:omit]}/\n" if options[:omit]
|
|
83
|
+
return paths.join
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Root passed, so show all matches
|
|
87
|
+
|
|
88
|
+
paths = paths.select{|o| o =~ /^- #{Notes::LABEL_REGEX}#{path}\/./}
|
|
89
|
+
|
|
90
|
+
bullet = options[:quoted] ? "|" : "-"
|
|
91
|
+
|
|
92
|
+
if options[:exclude_path]
|
|
93
|
+
paths.each{|o| o.sub! /^- (#{Notes::LABEL_REGEX})#{path}\//, "#{bullet} \\1"}
|
|
94
|
+
paths = paths.select{|o| o != "#{bullet} "}
|
|
95
|
+
else
|
|
96
|
+
paths = paths.map{|o| o.sub /^- #{Notes::LABEL_REGEX}/, '\\0@'}
|
|
97
|
+
end
|
|
98
|
+
paths = paths.reverse.uniq
|
|
99
|
+
paths.delete_if{|o| o == "| \n"}
|
|
100
|
+
paths.join
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.log
|
|
104
|
+
|
|
105
|
+
lines = IO.readlines self.log_file
|
|
106
|
+
|
|
107
|
+
# If parent, narrow down to just it
|
|
108
|
+
trunk = Xiki.trunk
|
|
109
|
+
if trunk.length > 1 && trunk[-2] != "menu/history" # Show all if under this menu
|
|
110
|
+
lines = lines.select {|o| o.start_with? "- #{trunk[-2]}"}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
lines.reverse.uniq.map{|o| o.sub /^- /, '<< '}.join
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.log_file
|
|
117
|
+
@@log
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.add *args, &block
|
|
121
|
+
arg = args.shift
|
|
122
|
+
|
|
123
|
+
raise "Launcher.add called with no args and no block" if args == [nil] && block.nil?
|
|
124
|
+
|
|
125
|
+
if arg.is_a? Regexp # If regex, add
|
|
126
|
+
@@launchers[arg] = block
|
|
127
|
+
elsif arg.is_a? Proc # If proc, add to procs
|
|
128
|
+
@@launchers_procs << [arg, block]
|
|
129
|
+
elsif arg.is_a?(String)
|
|
130
|
+
self.add_menu arg, args[0], block
|
|
131
|
+
else
|
|
132
|
+
raise "Don't know how to launch this"
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def self.add_menu root, hash, block
|
|
137
|
+
if hash.nil? && block # If just block, just define
|
|
138
|
+
return @@menus[1][root] = block
|
|
139
|
+
elsif hash.is_a?(Hash) && hash[:menu_file] && block
|
|
140
|
+
return @@menus[0][root] = block
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# If just root, we'll use use class with that name
|
|
144
|
+
if block.nil? && (hash.nil? || hash[:class])
|
|
145
|
+
clazz = hash ? hash[:class] : root
|
|
146
|
+
clazz.sub!(/(\w+)/) {TextUtil.snake_case $1} if hash
|
|
147
|
+
self.add root do |path|
|
|
148
|
+
# Make class me camel case, and change Launcher.invoke to Menu.call
|
|
149
|
+
Launcher.invoke clazz, path
|
|
150
|
+
end
|
|
151
|
+
return
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
menu = hash[:menu]
|
|
155
|
+
if menu
|
|
156
|
+
if menu =~ /\A\/.+\.\w+\z/ # If it's a file (1 line and has extension)
|
|
157
|
+
require_menu menu
|
|
158
|
+
return
|
|
159
|
+
elsif menu =~ /\A[\w \/-]+\z/ # If it's a menu to delegate to
|
|
160
|
+
self.add root do |path|
|
|
161
|
+
Menu.call menu, Tree.rootless(path)
|
|
162
|
+
end
|
|
163
|
+
return
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
self.add root do |path| # If text of the actual menu
|
|
167
|
+
# Different from Menu[...] or .drill?
|
|
168
|
+
Tree.children menu, Tree.rootless(path)
|
|
169
|
+
end
|
|
170
|
+
return
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
raise "Don't know how to deal with: #{root}, #{hash}, #{block}"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def self.launch_or_hide options={}
|
|
177
|
+
# If no prefixes and children exist, delete under
|
|
178
|
+
if ! Keys.prefix and ! Line.blank? and Tree.children?
|
|
179
|
+
Tree.minus_to_plus
|
|
180
|
+
Tree.kill_under
|
|
181
|
+
return
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Else, launch
|
|
185
|
+
self.launch options
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def self.hide
|
|
189
|
+
Tree.kill_under
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Call the appropriate launcher if we find one, passing it line
|
|
193
|
+
def self.launch options={}
|
|
194
|
+
|
|
195
|
+
# Add linebreak at end if at end of file and none
|
|
196
|
+
Line.<<("\n", :dont_move=>1) if Line.right == View.bottom
|
|
197
|
+
|
|
198
|
+
Tree.plus_to_minus unless options[:leave_bullet]
|
|
199
|
+
|
|
200
|
+
Line.sub! /^\.$/, './'
|
|
201
|
+
Line.sub! /^~$/, '~/'
|
|
202
|
+
|
|
203
|
+
# Maybe don't blink when in $__small_menu_box!"
|
|
204
|
+
Effects.blink(:what=>:line) if options[:blink]
|
|
205
|
+
line = options[:line] || Line.value # Get paren from line
|
|
206
|
+
label = Line.label(line)
|
|
207
|
+
|
|
208
|
+
if line =~ /^ *@$/
|
|
209
|
+
matches = Launcher.menu_keys
|
|
210
|
+
Tree.<< matches.sort.map{|o| "<< #{o.sub '_', ' '}/"}.join("\n"), :no_slash=>1
|
|
211
|
+
return
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Special hooks for specific files and modes
|
|
215
|
+
return if self.file_and_mode_hooks
|
|
216
|
+
|
|
217
|
+
$xiki_no_search = options[:no_search] # If :no_search, disable search
|
|
218
|
+
|
|
219
|
+
is_root = false
|
|
220
|
+
|
|
221
|
+
if line =~ /^( *)[+-] [^\n\(]+?\) (.+)/ # Split off label, if there
|
|
222
|
+
line = $1 + $2
|
|
223
|
+
end
|
|
224
|
+
if line =~ /^( *)[+-] (.+)/ # Split off bullet, if there
|
|
225
|
+
line = $1 + $2
|
|
226
|
+
end
|
|
227
|
+
if line =~ /^ *@ ?(.+)/ # Split off @ and indent if @ exists
|
|
228
|
+
is_root = true
|
|
229
|
+
line = $1
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Special case to turn launchers back on
|
|
233
|
+
return self.show_or_launch if line == "launcher/setup/show or launch/"
|
|
234
|
+
|
|
235
|
+
@@launchers.each do |regex, block| # Try each potential regex match
|
|
236
|
+
# If we found a match, launch it
|
|
237
|
+
if line =~ regex
|
|
238
|
+
group = $1
|
|
239
|
+
|
|
240
|
+
# Run it
|
|
241
|
+
if @@just_show
|
|
242
|
+
Ol << "- regex: #{regex.to_s}\n- group: #{group}"
|
|
243
|
+
else
|
|
244
|
+
|
|
245
|
+
begin
|
|
246
|
+
block.call line
|
|
247
|
+
rescue RelinquishException
|
|
248
|
+
next # They didn't want to handle it, keep going
|
|
249
|
+
rescue Exception=>e
|
|
250
|
+
Tree.<< CodeTree.draw_exception(e, block.to_ruby), :no_slash=>true
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
end
|
|
254
|
+
$xiki_no_search = false
|
|
255
|
+
return true
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# If current line is indented and not passed recursively yet, try again, passing tree
|
|
260
|
+
|
|
261
|
+
if Line.value =~ /^ / && ! options[:line] && !is_root # If indented, call .launch recursively
|
|
262
|
+
|
|
263
|
+
# Use Xiki.branch here? (breaks up by @'s)
|
|
264
|
+
|
|
265
|
+
# merge together (spaces if no slashes) and pass that to launch
|
|
266
|
+
|
|
267
|
+
list = Tree.construct_path :list=>true, :ignore_ol=>1 # Get path to pass to procs, to help them decide
|
|
268
|
+
|
|
269
|
+
found = list.index{|o| o =~ /^@/} and list = list[found..-1] # Remove before @... node if any
|
|
270
|
+
merged = list.map{|o| o.sub /\/$/, ''}.join('/')
|
|
271
|
+
merged << "/" if list[-1] =~ /\/$/
|
|
272
|
+
|
|
273
|
+
# Recursively call again with full path
|
|
274
|
+
return self.launch options.merge(:line=>merged)
|
|
275
|
+
|
|
276
|
+
# What was this doing, did we mean to only pass on :no_search??
|
|
277
|
+
# return self.launch options.slice(:no_search).merge(:line=>merged)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
if self.launch_by_proc # Try procs (currently all trees)
|
|
281
|
+
return $xiki_no_search = false
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# If nothing found so far, don't do anything if...
|
|
285
|
+
if line =~ /^\|/
|
|
286
|
+
View.beep
|
|
287
|
+
return View.message "Don't know what to do with this line"
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# See if it matches path launcher
|
|
291
|
+
|
|
292
|
+
self.set_env_vars line
|
|
293
|
+
|
|
294
|
+
result = self.try_menu_launchers line, options
|
|
295
|
+
self.unset_env_vars
|
|
296
|
+
return if result
|
|
297
|
+
|
|
298
|
+
if line =~ /^([\w -]*)$/ || line =~ /^([\w -]*)\.\.\.\/?$/
|
|
299
|
+
|
|
300
|
+
# if line =~ /^([\w -]*)(\.\.\.)?\/?$/
|
|
301
|
+
# TODO just check for exact match in dir, and load it if no launcher yet!
|
|
302
|
+
|
|
303
|
+
root = $1
|
|
304
|
+
root.gsub!(/[ -]/, '_') if root
|
|
305
|
+
matches = self.menu_keys.select do |possibility|
|
|
306
|
+
possibility =~ /^#{root}/
|
|
307
|
+
end
|
|
308
|
+
if matches.any?
|
|
309
|
+
if matches.length == 1
|
|
310
|
+
match = matches[0].gsub '_', ' '
|
|
311
|
+
Line.sub! /^([ @+-]*).*/, "\\1#{match}"
|
|
312
|
+
Launcher.launch
|
|
313
|
+
return
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
Line.sub! /\b$/, "..."
|
|
317
|
+
|
|
318
|
+
View.under matches.sort.map{|o| "<< #{o.sub '_', ' '}/"}.join("\n")
|
|
319
|
+
return
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# If just root line, load any unloaded launchers this completes and relaunch
|
|
324
|
+
|
|
325
|
+
# Failed attempt to not auto-complete if slash
|
|
326
|
+
# It's tough because we still want to load!
|
|
327
|
+
# Don't do if ends with slash? - does this mean it won't load unloaded?
|
|
328
|
+
|
|
329
|
+
if line =~ /^([\w -]+)\/?$/ && ! options[:recursed]
|
|
330
|
+
root = $1
|
|
331
|
+
root.gsub!(/[ -]/, '_') if root
|
|
332
|
+
|
|
333
|
+
["~/menus", Bookmarks["$x/menus"]].each do |dir|
|
|
334
|
+
|
|
335
|
+
matches = Dir[File.expand_path("#{dir}/#{root}*")]
|
|
336
|
+
|
|
337
|
+
if matches.any?
|
|
338
|
+
matches.sort.each do |file|
|
|
339
|
+
iroot = file[/\/(\w+)\./, 1]
|
|
340
|
+
next if @@menus[0][root] || @@menus[1][root] # Skip if already loaded
|
|
341
|
+
require_menu(file) # if File.exists? file
|
|
342
|
+
end
|
|
343
|
+
return self.launch :recursed=>1 # options.slice(:no_search).merge(:line=>merged)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
if root = line[/^[\w -]+/]
|
|
350
|
+
Xiki.dont_search
|
|
351
|
+
# Maybe make the following print out optionally, via a 'help_last' block?
|
|
352
|
+
Tree << "
|
|
353
|
+
| There's no \"#{root}\" menu yet. Create it? You can start by adding items
|
|
354
|
+
| right here, or you can create a class.
|
|
355
|
+
<= @menu/create/here/
|
|
356
|
+
<= @menu/create/class/
|
|
357
|
+
<= @menu/install/gem/
|
|
358
|
+
"
|
|
359
|
+
else
|
|
360
|
+
View.flash "- No launcher matched!"
|
|
361
|
+
end
|
|
362
|
+
$xiki_no_search = false
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def self.try_menu_launchers line, options={}
|
|
366
|
+
|
|
367
|
+
# If there's a /@ in the path, cut it off
|
|
368
|
+
line.sub! /.+\/@/, ''
|
|
369
|
+
|
|
370
|
+
root_orig = root = line[/^[\w -]+/] # Grab thing to match
|
|
371
|
+
root = TextUtil.snake_case root if root
|
|
372
|
+
|
|
373
|
+
self.append_log line
|
|
374
|
+
trunk = Xiki.trunk
|
|
375
|
+
|
|
376
|
+
# If menu nested under dir or file, chdir first
|
|
377
|
+
|
|
378
|
+
orig_pwd = nil
|
|
379
|
+
if trunk.size > 1 && closest_dir = Tree.closest_dir
|
|
380
|
+
orig_pwd = Dir.pwd # Where ruby pwd was before
|
|
381
|
+
|
|
382
|
+
if root == "mkdir"
|
|
383
|
+
Dir.chdir "/tmp/"
|
|
384
|
+
elsif File.directory?(closest_dir) || is_file = File.file?(closest_dir) # If dir path
|
|
385
|
+
closest_dir = File.dirname closest_dir if is_file
|
|
386
|
+
|
|
387
|
+
Dir.chdir closest_dir
|
|
388
|
+
|
|
389
|
+
# If file, make path only have dir
|
|
390
|
+
# remove file
|
|
391
|
+
|
|
392
|
+
else # If doesn't exist
|
|
393
|
+
View.beep "- Dir doesn't exist: #{closest_dir}"
|
|
394
|
+
return true
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
# If there is a matching .menu, use it
|
|
399
|
+
|
|
400
|
+
out = nil
|
|
401
|
+
if block_dot_menu = @@menus[0][root]
|
|
402
|
+
|
|
403
|
+
if @@just_show
|
|
404
|
+
Ol.line "Maps to .menu file, for menu: #{root}\n - #{block_dot_menu}\n - #{block_dot_menu.to_ruby}"
|
|
405
|
+
View.flash "- Showed launcher in $o", :times=>4
|
|
406
|
+
return true # To make it stop trying to run it
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
begin
|
|
410
|
+
out = Tree.output_and_search block_dot_menu, :line=>line #, :dir=>file_path
|
|
411
|
+
ensure
|
|
412
|
+
Dir.chdir orig_pwd if orig_pwd
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# If .menu file matched but had no output, and no other block to delegate to, say we handled it so it will stop looking
|
|
416
|
+
|
|
417
|
+
if ! out
|
|
418
|
+
require_menu File.expand_path("~/menus/#{root}.rb"), :ok_if_not_found=>1
|
|
419
|
+
if ! @@menus[1][root]
|
|
420
|
+
Tree << "
|
|
421
|
+
| This menu item does nothing yet. You can update the .menu file to
|
|
422
|
+
| give it children or create a class to give it dynamic behavior:
|
|
423
|
+
<= @menu/create/class/
|
|
424
|
+
"
|
|
425
|
+
return true
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
return true if out # Output means we handled it, otherwise continue on and try class
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# If there is a matching .rb for the menu, use it
|
|
432
|
+
|
|
433
|
+
if block_other = @@menus[1][root] # If class menu
|
|
434
|
+
|
|
435
|
+
if @@just_show
|
|
436
|
+
Ol.line << "Maps to class or other block, for menu: #{root}\n - #{block_other}\n - #{block_other.to_ruby}"
|
|
437
|
+
View.flash "- Showed launcher in $o", :times=>4
|
|
438
|
+
return true # To make it stop trying to run it
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
begin
|
|
442
|
+
Tree.output_and_search block_other, options.merge(:line=>line) #, :dir=>file_path
|
|
443
|
+
ensure
|
|
444
|
+
Dir.chdir orig_pwd if orig_pwd
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
return true
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# If uppercase, try invoking on in-memory class
|
|
451
|
+
if root_orig =~ /^[A-Z]/
|
|
452
|
+
|
|
453
|
+
if @@just_show
|
|
454
|
+
Ol.line << "Maps to in-memory class for: #{root}"
|
|
455
|
+
View.flash "- Showed launcher in $o", :times=>4
|
|
456
|
+
return true # To make it stop trying to run it
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
begin
|
|
460
|
+
|
|
461
|
+
lam = lambda do |path|
|
|
462
|
+
Launcher.invoke root_orig, path
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Launcher.invoke__
|
|
466
|
+
# do |path|
|
|
467
|
+
# # Make class me camel case, and change Launcher.invoke to Menu.call
|
|
468
|
+
# end
|
|
469
|
+
|
|
470
|
+
Tree.output_and_search lam, options.merge(:line=>line) #, :dir=>file_path
|
|
471
|
+
ensure
|
|
472
|
+
Dir.chdir orig_pwd if orig_pwd
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
return true
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Pull into other function?
|
|
479
|
+
# re-use code that calls class wrapper
|
|
480
|
+
|
|
481
|
+
false # No match, keep looking
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def self.launch_by_proc list=nil
|
|
485
|
+
list = Tree.construct_path(:list=>true) # Get path to pass to procs, to help them decide
|
|
486
|
+
|
|
487
|
+
# Try each proc
|
|
488
|
+
@@launchers_procs.each do |launcher| # For each potential match
|
|
489
|
+
condition_proc, block = launcher
|
|
490
|
+
if found = condition_proc.call(list) # If we found a match, launch it
|
|
491
|
+
if @@just_show
|
|
492
|
+
Ol << condition_proc.to_ruby
|
|
493
|
+
else
|
|
494
|
+
block.call list[found..-1]
|
|
495
|
+
end
|
|
496
|
+
return true
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
return false
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def self.init_default_launchers
|
|
503
|
+
|
|
504
|
+
self.add(/^\$ /) do |l| # $ shell command inline (sync)
|
|
505
|
+
Console.launch :sync=>true
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
self.add /^%( |$)/ do # % shell command (async)
|
|
509
|
+
Console.launch_async
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
self.add /^&( |$)/ do # % shell command in iterm
|
|
513
|
+
Console.launch_async :iterm=>1
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# %\n | multiline\n | commands
|
|
517
|
+
Launcher.add /^\%\// do # For % with nested quoted lines
|
|
518
|
+
path = Tree.construct_path :list=>1
|
|
519
|
+
|
|
520
|
+
next if path[-1] !~ /^\| /
|
|
521
|
+
|
|
522
|
+
txt = Tree.siblings :string=>1
|
|
523
|
+
|
|
524
|
+
orig = Location.new
|
|
525
|
+
Console.to_shell_buffer
|
|
526
|
+
View.to_bottom
|
|
527
|
+
Console.enter txt
|
|
528
|
+
orig.go
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
self.add(/^(http|file).?:\/\/.+/) do |path|
|
|
532
|
+
Launcher.append_log "- http/#{path}"
|
|
533
|
+
|
|
534
|
+
prefix = Keys.prefix
|
|
535
|
+
Keys.clear_prefix
|
|
536
|
+
|
|
537
|
+
url = path[/(http|file).?:\/\/.+/]
|
|
538
|
+
if prefix == "all"
|
|
539
|
+
txt = RestTree.request("GET", url)
|
|
540
|
+
txt = Tree.quote(txt) if txt =~ /\A<\w/
|
|
541
|
+
Tree.under txt, :no_slash=>1
|
|
542
|
+
next
|
|
543
|
+
end
|
|
544
|
+
url.gsub! '%', '%25'
|
|
545
|
+
url.gsub! '"', '%22'
|
|
546
|
+
prefix == :u ? $el.browse_url(url) : Firefox.url(url)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
self.add(/^\$[^ #*!\/]+$/) do |line| # Bookmark
|
|
550
|
+
View.open Line.without_indent(line)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
self.add(/^(p )?[A-Z][A-Za-z]+\.(\/|$)/) do |line|
|
|
554
|
+
line.sub! /^p /, ''
|
|
555
|
+
Code.launch_dot_at_end line
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
self.add(/^p /) do |line|
|
|
559
|
+
CodeTree.run line
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
self.add(/^ *pp /) do |line|
|
|
563
|
+
CodeTree.run line
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
self.add(/^ *puts /) do |line|
|
|
567
|
+
CodeTree.run line
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
self.add(/^ *print\(/) do |line|
|
|
571
|
+
Javascript.launch
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
self.add(/^ *$/) do |line| # Empty line
|
|
575
|
+
View.beep
|
|
576
|
+
View.message "There was nothing on this line to launch."
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
self.add(/^\*$/) do |line| # *... buffer
|
|
580
|
+
Line.sub! /.+/, "all"
|
|
581
|
+
|
|
582
|
+
Launcher.launch
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
self.add(/^\*./) do |line| # *... buffer
|
|
586
|
+
name = Line.without_label.sub(/\*/, '')
|
|
587
|
+
View.to_after_bar
|
|
588
|
+
View.to_buffer name
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Must have at least 2 slashes!
|
|
592
|
+
self.add(/^[^\|@:]+\/\w+\/[\/\w\-]+\.\w+:\d+/) do |line| # Stack traces, etc
|
|
593
|
+
# Match again (necessary)
|
|
594
|
+
line =~ /([$\/.\w\-]+):(\d+)/
|
|
595
|
+
path, line = $1, $2
|
|
596
|
+
|
|
597
|
+
# If relative dir, prepend current dir
|
|
598
|
+
if path =~ /^\w/
|
|
599
|
+
path = "#{View.dir}/#{path}"
|
|
600
|
+
path.sub! "//", "/" # View.dir sometimes ends with slash
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
View.open path
|
|
604
|
+
View.to_line line.to_i
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
# Xiki protocol to server
|
|
608
|
+
self.add(/^[a-z-]{2,}\.(com|net|org|loc|in|edu|gov|uk)(\/|$)/) do |line| # **.../: Tree grep in dir
|
|
609
|
+
self.web_menu line
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
self.add(/^localhost:?\d*(\/|$)/) do |line|
|
|
613
|
+
self.web_menu line
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
self.add(/^ *(Ol\.line|Ol << )/) do
|
|
617
|
+
View.layout_output :called_by_launch=>1
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
# Example code in method comments
|
|
621
|
+
# /tmp/foo.rb
|
|
622
|
+
# class Foo
|
|
623
|
+
# # Control-enter to run this line
|
|
624
|
+
# # Foo.bar
|
|
625
|
+
# def self.bar
|
|
626
|
+
Launcher.add /^class (\w+)\/\#.+/ do |path|
|
|
627
|
+
# Remove comment and run
|
|
628
|
+
txt = Line.value.sub /^ +# /, ''
|
|
629
|
+
result = Code.eval(txt)
|
|
630
|
+
next Tree.<<(CodeTree.draw_exception(result[2], txt), :no_search=>1) if result[2]
|
|
631
|
+
next Tree.<< result[0].to_s, :no_slash=>1 if result[0] # Returned value
|
|
632
|
+
Tree.<< result[1].to_s, :no_slash=>1 if result[1].any? # Stdout
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
Launcher.add /^class (\w+)\/def self.menu\/(.+)/ do |path|
|
|
636
|
+
clazz, path = path.match(/^class (\w+)\/def self.menu\/(.+)/)[1..2]
|
|
637
|
+
|
|
638
|
+
path = "#{TextUtil.snake_case clazz}/#{path}".gsub("/.", '/')
|
|
639
|
+
|
|
640
|
+
Tree << Menu[path]
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
Launcher.add /^ +<+@ .+/ do
|
|
644
|
+
Menu.root_collapser_launcher
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
Launcher.add /^ +<+ .+/ do
|
|
648
|
+
Menu.collapser_launcher
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
Launcher.add /^ +<+= .+/ do
|
|
652
|
+
Menu.replacer_launcher
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
Launcher.add /^[a-z]+\+[a-z+]+\/?$/ do |path|
|
|
656
|
+
Tree << %`
|
|
657
|
+
| If you were told to "type #{path}", it is meant that you should
|
|
658
|
+
| "type the acronym" while holding down control. This means Meaning
|
|
659
|
+
| you should type:
|
|
660
|
+
|
|
|
661
|
+
| #{Keys.human_readable(path)}
|
|
662
|
+
`
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# Menu launchers
|
|
666
|
+
|
|
667
|
+
Launcher.add "log" do # |path|
|
|
668
|
+
Launcher.log# Tree.rootless(path)
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
Launcher.add "last" do |path|
|
|
672
|
+
Launcher.last path
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
# ...Tree classes
|
|
676
|
+
|
|
677
|
+
# RestTree
|
|
678
|
+
condition_proc = proc {|list| RestTree.handles? list}
|
|
679
|
+
Launcher.add condition_proc do |list|
|
|
680
|
+
RestTree.launch :path=>list
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# FileTree
|
|
684
|
+
condition_proc = proc {|list| FileTree.handles? list}
|
|
685
|
+
Launcher.add condition_proc do |list|
|
|
686
|
+
FileTree.launch list
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
# CodeTree
|
|
690
|
+
condition_proc = proc {|list| CodeTree.handles? list}
|
|
691
|
+
Launcher.add condition_proc do |list|
|
|
692
|
+
CodeTree.launch :path=>list
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# UrlTree
|
|
696
|
+
condition_proc = proc {|list| UrlTree.handles? list}
|
|
697
|
+
Launcher.add condition_proc do |list|
|
|
698
|
+
UrlTree.launch :path=>list
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
def self.file_and_mode_hooks
|
|
703
|
+
if View.mode == :dired_mode
|
|
704
|
+
filename = $el.dired_get_filename
|
|
705
|
+
# If dir, open tree
|
|
706
|
+
if File.directory?(filename)
|
|
707
|
+
FileTree.ls :dir=>filename
|
|
708
|
+
else # If file, do full file search?
|
|
709
|
+
History.open_current :all => true, :paths => [filename]
|
|
710
|
+
end
|
|
711
|
+
return true
|
|
712
|
+
end
|
|
713
|
+
if View.name =~ /^\*ol/ # If in an ol output log file
|
|
714
|
+
OlHelper.launch
|
|
715
|
+
Effects.blink(:what=>:line)
|
|
716
|
+
return true
|
|
717
|
+
end
|
|
718
|
+
return false
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
def self.do_last_launch options={}
|
|
722
|
+
orig = View.index
|
|
723
|
+
|
|
724
|
+
CLEAR_CONSOLES.each do |buffer|
|
|
725
|
+
View.clear buffer
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
prefix = Keys.prefix :clear=>true
|
|
729
|
+
|
|
730
|
+
if prefix ==:u || options[:here]
|
|
731
|
+
View.to_nth orig
|
|
732
|
+
else
|
|
733
|
+
Move.to_window 1
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
line = Line.value
|
|
737
|
+
|
|
738
|
+
# Go to parent and collapse, if not at left margin, and buffer modified (shows we recently inserted)
|
|
739
|
+
if ! Color.at_cursor.member?("color-rb-light") #&& line !~ /^ *[+-] / # and not a bullet
|
|
740
|
+
if line =~ /^ /
|
|
741
|
+
Tree.to_parent
|
|
742
|
+
end
|
|
743
|
+
Tree.kill_under
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
Launcher.launch_or_hide :blink=>true, :no_search=>true
|
|
747
|
+
View.to_nth orig
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
# Used any more? - should be replaced by menu log - delete this
|
|
751
|
+
def self.urls
|
|
752
|
+
txt = File.read File.expand_path("~/.emacs.d/url_log.notes")
|
|
753
|
+
txt = txt.split("\n").reverse.uniq.join("\n")
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
def self.enter_last_launched
|
|
757
|
+
Launcher.insert self.last_launched_menu
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
def self.last_launched_menu
|
|
761
|
+
bm = Keys.input(:timed => true, :prompt => "bookmark to show launches for (* for all): ")
|
|
762
|
+
|
|
763
|
+
menu =
|
|
764
|
+
if bm == "8" || bm == " "
|
|
765
|
+
"- search/launched/"
|
|
766
|
+
elsif bm == "."
|
|
767
|
+
"- Search.launched '#{View.file}'/"
|
|
768
|
+
elsif bm == "3"
|
|
769
|
+
"- Search.launched '#'/"
|
|
770
|
+
elsif bm == ";" || bm == ":" || bm == "-"
|
|
771
|
+
"- Search.launched ':'/"
|
|
772
|
+
else
|
|
773
|
+
"- search/launched/$#{bm}/"
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
def self.invoke clazz, path, options={}
|
|
778
|
+
|
|
779
|
+
default_method = "menu"
|
|
780
|
+
# If dot, extract it as method
|
|
781
|
+
if clazz =~ /\./
|
|
782
|
+
clazz, default_method = clazz.match(/(.+)\.(.+)/)[1..2]
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
if clazz.is_a? String
|
|
786
|
+
# Require it to be camel case (because .invoke will be Menu.call "Class"
|
|
787
|
+
# if lower case, will assume Menu.call "path"
|
|
788
|
+
camel = TextUtil.camel_case clazz
|
|
789
|
+
clazz = $el.instance_eval(camel, __FILE__, __LINE__) rescue nil
|
|
790
|
+
|
|
791
|
+
elsif clazz.is_a? Class
|
|
792
|
+
camel = clazz.to_s
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
snake = TextUtil.snake_case camel
|
|
796
|
+
|
|
797
|
+
raise "No class '#{clazz || camel}' found in launcher" if clazz.nil?
|
|
798
|
+
|
|
799
|
+
# reload 'path_to_class'
|
|
800
|
+
Menu.load_if_changed File.expand_path("~/menus/#{snake}.rb")
|
|
801
|
+
|
|
802
|
+
args = path.is_a?(Array) ?
|
|
803
|
+
path : Menu.split(path, :rootless=>1)
|
|
804
|
+
|
|
805
|
+
# Call .menu_before if there...
|
|
806
|
+
|
|
807
|
+
method = clazz.method("menu_before") rescue nil
|
|
808
|
+
|
|
809
|
+
self.set_env_vars path
|
|
810
|
+
|
|
811
|
+
if method
|
|
812
|
+
code = "#{camel}.menu_before *#{args.inspect}"
|
|
813
|
+
returned, out, exception = Code.eval code
|
|
814
|
+
|
|
815
|
+
return CodeTree.draw_exception exception, code if exception
|
|
816
|
+
if returned
|
|
817
|
+
|
|
818
|
+
# TODO: call .unset_env_vars before this and other below places we return
|
|
819
|
+
|
|
820
|
+
returned = returned.unindent if returned =~ /\A[ \n]/
|
|
821
|
+
return returned
|
|
822
|
+
end
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
menu_arity = nil
|
|
826
|
+
txt = options[:tree]
|
|
827
|
+
|
|
828
|
+
# Call .menu with no args to get child menus or route to other method...
|
|
829
|
+
|
|
830
|
+
if txt.nil?
|
|
831
|
+
method = clazz.method(default_method) rescue nil
|
|
832
|
+
if method && method.arity == 0
|
|
833
|
+
menu_arity = 0
|
|
834
|
+
code = "#{camel}.#{default_method}"
|
|
835
|
+
returned, out, exception = Code.eval code
|
|
836
|
+
return CodeTree.draw_exception exception, code if exception
|
|
837
|
+
txt = CodeTree.returned_to_s returned # Convert from array into string, etc.
|
|
838
|
+
end
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
# Error if no menu method or file
|
|
842
|
+
if method.nil? && txt.nil? && ! args.find{|o| o =~ /^\./}
|
|
843
|
+
|
|
844
|
+
cmethods = clazz.methods - Class.methods
|
|
845
|
+
return cmethods.sort.map{|o| ".#{o}/"}
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
# If got routable menu text, use it to route (get children or dotify)...
|
|
850
|
+
|
|
851
|
+
if txt
|
|
852
|
+
txt = txt.unindent if txt =~ /\A[ \n]/
|
|
853
|
+
raise "#{code} returned nil, but is supposed to return something when it takes no arguments" if txt.nil?
|
|
854
|
+
|
|
855
|
+
tree = txt
|
|
856
|
+
|
|
857
|
+
txt = Tree.children tree, args
|
|
858
|
+
|
|
859
|
+
if txt && txt != "- */\n"
|
|
860
|
+
# Pass in output of menu as either:
|
|
861
|
+
# ENV['output']
|
|
862
|
+
# 1st parameter: .menu_after output, *args
|
|
863
|
+
return self.invoke_menu_after clazz, txt, args
|
|
864
|
+
end
|
|
865
|
+
|
|
866
|
+
# Copy dots onto args, so last dotted one will be used as action
|
|
867
|
+
|
|
868
|
+
Tree.dotify! tree, args
|
|
869
|
+
|
|
870
|
+
# TODO: when to invoke this?
|
|
871
|
+
# Maybe invoke even if there was no .menu method
|
|
872
|
+
# Is that happening now?
|
|
873
|
+
|
|
874
|
+
# If .menu_hidden exists, dotify based on its output as well...
|
|
875
|
+
method = clazz.method("menu_hidden") rescue nil
|
|
876
|
+
if method
|
|
877
|
+
returned, out, exception = Code.eval "#{camel}.menu_hidden"
|
|
878
|
+
|
|
879
|
+
if returned && returned.is_a?(String)
|
|
880
|
+
returned = returned.unindent
|
|
881
|
+
Tree.dotify! returned, args
|
|
882
|
+
end
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
end
|
|
886
|
+
# Else, continue on to run it based on routified path
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
# TODO: Maybe extract this out into .dotified_to_ruby ?
|
|
890
|
+
|
|
891
|
+
# Figure out which ones are actions
|
|
892
|
+
|
|
893
|
+
# Last .dotted one is the action, and non-dotted are variables to pass
|
|
894
|
+
actions, variables = args.partition{|o| o =~ /^\./ }
|
|
895
|
+
action = actions.last || ".#{default_method}"
|
|
896
|
+
action.gsub! /[ -]/, '_'
|
|
897
|
+
action.gsub! /[^\w.]/, ''
|
|
898
|
+
|
|
899
|
+
# Call .menu_after if appropriate...
|
|
900
|
+
|
|
901
|
+
if action == ".menu" && txt == nil && menu_arity == 0
|
|
902
|
+
return self.invoke_menu_after clazz, txt, args
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
args = variables.map{|o| "\"#{CodeTree.escape o}\""}.join(", ")
|
|
906
|
+
|
|
907
|
+
# TODO: use adapter here, so we can call .js file?
|
|
908
|
+
|
|
909
|
+
# TODO .menu_after: Check for arity - if mismatch, don't call, but go straight to .menu_after!
|
|
910
|
+
# We could probably not worry about this for now?
|
|
911
|
+
|
|
912
|
+
code = "#{camel}#{action.downcase} #{args}".strip
|
|
913
|
+
|
|
914
|
+
txt, out, exception = Code.eval code
|
|
915
|
+
txt = CodeTree.returned_to_s(txt) # Convert from array into string, etc.
|
|
916
|
+
self.unset_env_vars
|
|
917
|
+
|
|
918
|
+
txt = txt.unindent if txt =~ /\A[ \n]/
|
|
919
|
+
|
|
920
|
+
return CodeTree.draw_exception exception, code if exception
|
|
921
|
+
|
|
922
|
+
txt = self.invoke_menu_after clazz, txt, args
|
|
923
|
+
|
|
924
|
+
self.unset_env_vars
|
|
925
|
+
|
|
926
|
+
txt
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
def self.invoke_menu_after clazz, txt, args
|
|
930
|
+
camel = clazz.to_s
|
|
931
|
+
method = clazz.method("menu_after") rescue nil
|
|
932
|
+
return txt if method.nil?
|
|
933
|
+
|
|
934
|
+
code = "#{camel}.menu_after #{txt.inspect}, *#{args.inspect}"
|
|
935
|
+
returned, out, exception = Code.eval code
|
|
936
|
+
|
|
937
|
+
return CodeTree.draw_exception exception, code if exception
|
|
938
|
+
if returned
|
|
939
|
+
|
|
940
|
+
# TODO: call .unset_env_vars before this and other below places we return
|
|
941
|
+
|
|
942
|
+
returned = returned.unindent if returned =~ /\A[ \n]/
|
|
943
|
+
return returned
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
txt # Otherwise, just return output!"
|
|
947
|
+
|
|
948
|
+
end
|
|
949
|
+
|
|
950
|
+
def self.add_class_launchers classes
|
|
951
|
+
classes.each do |clazz|
|
|
952
|
+
next if clazz =~ /\//
|
|
953
|
+
|
|
954
|
+
# Why is this line causing an error??
|
|
955
|
+
# clazz = $el.el4r_ruby_eval(TextUtil.camel_case clazz) rescue nil
|
|
956
|
+
# method = clazz.method(:menu) rescue nil
|
|
957
|
+
# next if method.nil?
|
|
958
|
+
|
|
959
|
+
self.add clazz do |path|
|
|
960
|
+
Launcher.invoke clazz, path
|
|
961
|
+
end
|
|
962
|
+
end
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
def self.append_log path
|
|
966
|
+
return if View.name =~ /_log.notes$/
|
|
967
|
+
|
|
968
|
+
path = path.sub /^[+-] /, '' # Remove bullet
|
|
969
|
+
path = "#{path}/" if path !~ /\// # Append slash if just root without path
|
|
970
|
+
|
|
971
|
+
return if path =~ /^(h|log|last)\//
|
|
972
|
+
|
|
973
|
+
path = "- #{path}"
|
|
974
|
+
File.open(@@log, "a") { |f| f << "#{path}\n" } rescue nil
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
#
|
|
978
|
+
# Insert menu right here and launch it
|
|
979
|
+
#
|
|
980
|
+
# Launcher.open "computer"
|
|
981
|
+
#
|
|
982
|
+
def self.insert txt, options={}
|
|
983
|
+
View.insert txt
|
|
984
|
+
$el.open_line(1)
|
|
985
|
+
Launcher.launch options
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
def self.show menu, options={}
|
|
989
|
+
self.open menu, options.merge(:no_launch=>1)
|
|
990
|
+
end
|
|
991
|
+
|
|
992
|
+
#
|
|
993
|
+
# Open new buffer and launch the menu in it
|
|
994
|
+
#
|
|
995
|
+
# Launcher.open "computer"
|
|
996
|
+
#
|
|
997
|
+
def self.open menu, options={}
|
|
998
|
+
return self.insert(menu, options) if options[:inline]
|
|
999
|
+
|
|
1000
|
+
$el.sit_for 0.25 if options[:delay] || options[:first_letter] # Delay slightly, (avoid flicking screen when they type command quickly)
|
|
1001
|
+
|
|
1002
|
+
View.to_after_bar if View.in_bar? && !options[:bar_is_fine]
|
|
1003
|
+
|
|
1004
|
+
dir = View.dir
|
|
1005
|
+
|
|
1006
|
+
# For buffer name, handle multi-line strings
|
|
1007
|
+
buffer = menu.sub(/.+\n[ -]*/m, '').gsub(/[.,]/, '')
|
|
1008
|
+
buffer = "@" + buffer.sub(/^[+-] /, '')
|
|
1009
|
+
View.to_buffer buffer, :dir=>dir
|
|
1010
|
+
|
|
1011
|
+
View.clear
|
|
1012
|
+
Notes.mode
|
|
1013
|
+
View.wrap :off
|
|
1014
|
+
|
|
1015
|
+
txt = menu
|
|
1016
|
+
|
|
1017
|
+
if txt.blank?
|
|
1018
|
+
return View.insert("\n", :dont_move=>1)
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
dir = options[:dir] and txt = "- #{dir.sub /\/$/, ''}/\n - #{txt}"
|
|
1022
|
+
|
|
1023
|
+
View << txt
|
|
1024
|
+
|
|
1025
|
+
$el.open_line 1
|
|
1026
|
+
|
|
1027
|
+
if options[:choices]
|
|
1028
|
+
View.to_highest
|
|
1029
|
+
Tree.search
|
|
1030
|
+
return
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
if options[:no_launch]
|
|
1034
|
+
View.to_highest
|
|
1035
|
+
return
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
Launcher.launch options
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
def self.method_missing *args, &block
|
|
1042
|
+
|
|
1043
|
+
arg = args.shift
|
|
1044
|
+
|
|
1045
|
+
if block.nil?
|
|
1046
|
+
if args == [] # Trying to call menu with no args
|
|
1047
|
+
return Menu.call arg.to_s
|
|
1048
|
+
end
|
|
1049
|
+
if args.length == 1 && args[0].is_a?(String) # Trying to call menu with args / path?
|
|
1050
|
+
return
|
|
1051
|
+
end
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
raise "Menu.#{arg} called with no block and no args" if args == [] && block.nil?
|
|
1055
|
+
self.add arg.to_s, args[0], &block
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
def self.wrapper path
|
|
1059
|
+
|
|
1060
|
+
# If starts with bookmark, expand as file (not dir)
|
|
1061
|
+
|
|
1062
|
+
path = Bookmarks.expand path, :file_ok=>1
|
|
1063
|
+
|
|
1064
|
+
# TODO: make generic
|
|
1065
|
+
# TODO: load all the adapters and construct the "rb|js" part of the regex
|
|
1066
|
+
match = path.match(/(.+\/)(\w+)\.(rb|js|coffee|py|notes|menu|haml)\/(.*)/)
|
|
1067
|
+
if match
|
|
1068
|
+
dir, file, extension, path = match[1..4]
|
|
1069
|
+
# TODO: instead, call Launcher.invoke JsAdapter(dir, path), path
|
|
1070
|
+
self.send "wrapper_#{extension}", dir, "#{file}.#{extension}", path
|
|
1071
|
+
return true # Indicate we handled it
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
# For matches to filename instead of extensions?
|
|
1075
|
+
match = path.match(/(.+\/)(Rakefile)\/(.*)/)
|
|
1076
|
+
if match
|
|
1077
|
+
dir, file, path = match[1..4]
|
|
1078
|
+
# TODO: instead, call Launcher.invoke JsAdapter(dir, path), path
|
|
1079
|
+
self.send "wrapper_#{file.downcase}", dir, file, path
|
|
1080
|
+
return true # Indicate we handled it
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
return false
|
|
1084
|
+
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
def self.wrapper_rb dir, file, path
|
|
1088
|
+
output = Console.run "ruby #{Xiki.dir}/etc/wrappers/wrapper.rb #{file} \"#{path}\"", :sync=>1, :dir=>dir
|
|
1089
|
+
|
|
1090
|
+
# Sensible thing for now is to just do literal output
|
|
1091
|
+
# output = Tree.children output, path if path !~ /^\./
|
|
1092
|
+
|
|
1093
|
+
# How to know when to do children?!
|
|
1094
|
+
# Because it called .menu, and menu had no args
|
|
1095
|
+
# Make it set env var?
|
|
1096
|
+
|
|
1097
|
+
# output = Tree.children output, path
|
|
1098
|
+
|
|
1099
|
+
Tree << output
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
def self.wrapper_js dir, file, path
|
|
1103
|
+
output = Console.run "node #{Xiki.dir}etc/wrappers/wrapper.js \"#{dir}#{file}\" \"#{path}\"", :sync=>1, :dir=>dir
|
|
1104
|
+
output = Tree.children output, path
|
|
1105
|
+
Tree << output
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
def self.wrapper_coffee dir, file, path
|
|
1109
|
+
txt = CoffeeScript.to_js("#{dir}#{file}")
|
|
1110
|
+
tmp_file = "/tmp/tmp.js"
|
|
1111
|
+
File.open(tmp_file, "w") { |f| f << txt }
|
|
1112
|
+
|
|
1113
|
+
output = Console.run "node #{Xiki.dir}etc/wrappers/wrapper.js \"#{tmp_file}\" \"#{path}\"", :sync=>1, :dir=>dir
|
|
1114
|
+
output = Tree.children output, path
|
|
1115
|
+
Tree << output
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
def self.wrapper_notes dir, file, path
|
|
1119
|
+
if match = path.match(/^(\| .+)(\| .*)/)
|
|
1120
|
+
heading, content = match[1..2]
|
|
1121
|
+
# [nil, nil])[1..2]
|
|
1122
|
+
else
|
|
1123
|
+
heading, content = [path, nil]
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
heading = nil if heading.blank?
|
|
1127
|
+
|
|
1128
|
+
# heading, content = (path.match(/^(\| .+)(\| .*)/) || [nil, nil])[1..2]
|
|
1129
|
+
|
|
1130
|
+
dir = "#{dir}/" if dir !~ /\/$/
|
|
1131
|
+
output = Notes.drill "#{dir}#{file}", heading, content
|
|
1132
|
+
Tree << output
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
def self.wrapper_menu dir, file, path
|
|
1136
|
+
heading, content = (path.match(/^(\| .+)(\| .*)?/) || [nil, nil])[1..2]
|
|
1137
|
+
|
|
1138
|
+
# output = Menu.drill "#{dir}/#{file}", heading, content
|
|
1139
|
+
|
|
1140
|
+
# output = Tree.children File.read(file), Tree.rootless(path)
|
|
1141
|
+
output = Tree.children File.read("#{Bookmarks[dir]}/#{file}"), path
|
|
1142
|
+
|
|
1143
|
+
Tree << output
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
def self.wrapper_py dir, file, path
|
|
1147
|
+
output = Console.run "python #{Xiki.dir}etc/wrappers/wrapper.py \"#{dir}#{file}\" \"#{path}\"", :sync=>1, :dir=>dir
|
|
1148
|
+
output = Tree.children output, path if path !~ /^\./
|
|
1149
|
+
Tree << output
|
|
1150
|
+
end
|
|
1151
|
+
|
|
1152
|
+
def self.wrapper_haml dir, file, path
|
|
1153
|
+
|
|
1154
|
+
engine = Haml::Engine.new(File.read "#{dir}#{file}")
|
|
1155
|
+
|
|
1156
|
+
foos = ["foo1", "foo2", "foo3"]
|
|
1157
|
+
o = Object.new
|
|
1158
|
+
o.instance_eval do
|
|
1159
|
+
@foo = "Foooo"
|
|
1160
|
+
@foos = foos
|
|
1161
|
+
end
|
|
1162
|
+
|
|
1163
|
+
txt = engine.render(o, "foo"=>"Fooooooo", "foos"=>foos)
|
|
1164
|
+
|
|
1165
|
+
Tree << Tree.quote(txt)
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
def self.wrapper_rakefile dir, file, path
|
|
1169
|
+
|
|
1170
|
+
# If just file passed, show all tasks
|
|
1171
|
+
|
|
1172
|
+
if path.blank?
|
|
1173
|
+
txt = Console.sync "rake -T", :dir=>dir
|
|
1174
|
+
|
|
1175
|
+
txt = txt.scan(/^rake (.+?) *#/).flatten
|
|
1176
|
+
|
|
1177
|
+
Tree << txt.map{|o| "- #{o}/\n"}.join
|
|
1178
|
+
return
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
# Task name passed, so run it
|
|
1182
|
+
|
|
1183
|
+
path.sub! /\/$/, ''
|
|
1184
|
+
Console.run "rake #{path}", :dir=>dir
|
|
1185
|
+
nil
|
|
1186
|
+
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
def self.reload_menu_dirs
|
|
1190
|
+
Ol.stack
|
|
1191
|
+
MENU_DIRS.each do |dir|
|
|
1192
|
+
next unless File.directory? dir
|
|
1193
|
+
|
|
1194
|
+
Files.in_dir(dir).each do |f|
|
|
1195
|
+
next if f !~ /^[a-z].*\..*[a-z]$/ || f =~ /__/
|
|
1196
|
+
path = "#{dir}/#{f}"
|
|
1197
|
+
stem = f[/[^.]*/]
|
|
1198
|
+
self.add stem, :menu=>path
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
"- reloaded!"
|
|
1202
|
+
end
|
|
1203
|
+
|
|
1204
|
+
#
|
|
1205
|
+
# Launches "menu/item", first prompting for name. Used by search+like_menu
|
|
1206
|
+
# and other places.
|
|
1207
|
+
#
|
|
1208
|
+
# If matches substring, shows the possible matches and does an isearch.
|
|
1209
|
+
#
|
|
1210
|
+
# Menu.like_menu "htm"
|
|
1211
|
+
#
|
|
1212
|
+
def self.like_menu item, options={}
|
|
1213
|
+
|
|
1214
|
+
# return
|
|
1215
|
+
return if item.nil?
|
|
1216
|
+
|
|
1217
|
+
menu = Keys.input :timed=>true, :prompt=>"Enter menu to pass '#{item}' to (space if menu): "
|
|
1218
|
+
|
|
1219
|
+
return self.open(item, options) if menu == " " # Space means text is the menu
|
|
1220
|
+
|
|
1221
|
+
matches = self.menu_keys.select do |possibility|
|
|
1222
|
+
possibility =~ /^#{menu}/
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
if matches.length == 1
|
|
1226
|
+
return self.open("- #{matches[0]}/#{item}", options)
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
self.open(matches.map{|o| "- #{o}/#{item}\n"}.join(''), options.merge(:choices=>1))
|
|
1230
|
+
right = View.cursor
|
|
1231
|
+
Move.to_previous_paragraph
|
|
1232
|
+
# return
|
|
1233
|
+
Tree.search :left=>View.cursor, :right=>right
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
def self.search_like_menu
|
|
1237
|
+
txt = Search.stop
|
|
1238
|
+
self.like_menu txt
|
|
1239
|
+
end
|
|
1240
|
+
|
|
1241
|
+
def self.as_update
|
|
1242
|
+
Keys.prefix = "update"
|
|
1243
|
+
Launcher.launch :leave_bullet=>1
|
|
1244
|
+
end
|
|
1245
|
+
|
|
1246
|
+
def self.as_delete
|
|
1247
|
+
Keys.prefix = "delete"
|
|
1248
|
+
Launcher.launch
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
def self.as_open
|
|
1252
|
+
Keys.prefix = "open"
|
|
1253
|
+
Launcher.launch
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def self.enter_all
|
|
1257
|
+
return FileTree.enter_lines(/.*/) if Line.blank?
|
|
1258
|
+
|
|
1259
|
+
Keys.prefix = "all"
|
|
1260
|
+
Launcher.launch
|
|
1261
|
+
end
|
|
1262
|
+
|
|
1263
|
+
def self.enter_outline
|
|
1264
|
+
return FileTree.enter_lines if Line.blank? # Prompts for bookmark
|
|
1265
|
+
|
|
1266
|
+
# If there's a numeric prefix, add it
|
|
1267
|
+
Keys.add_prefix "outline"
|
|
1268
|
+
Launcher.launch
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
def self.set_env_vars path
|
|
1272
|
+
|
|
1273
|
+
return if ! $el
|
|
1274
|
+
|
|
1275
|
+
# TODO: I guess they'll need to be set from somewhere else as well?
|
|
1276
|
+
|
|
1277
|
+
ENV['prefix'] = Keys.prefix.to_s
|
|
1278
|
+
|
|
1279
|
+
args = path.is_a?(Array) ?
|
|
1280
|
+
path : Menu.split(path, :rootless=>1)
|
|
1281
|
+
|
|
1282
|
+
# ?? If any has ^|, then make sure current line has slash
|
|
1283
|
+
|
|
1284
|
+
quoted = args.find{|o| o =~ /^\|( |$)/}
|
|
1285
|
+
|
|
1286
|
+
if ! quoted
|
|
1287
|
+
return ENV['txt'] = args[-1]
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1290
|
+
# Quoted lines
|
|
1291
|
+
|
|
1292
|
+
txt = Tree.leaf("|") # Cheat to make it grab quoted
|
|
1293
|
+
ENV['txt'] = txt.length > 1_000_000 ? "*too long to put into env var*" : txt
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
def self.web_menu line
|
|
1297
|
+
Line << "/" unless Line =~ /\/$/
|
|
1298
|
+
url = "http://#{line}"
|
|
1299
|
+
url.sub! /\.\w+/, "\\0/xiki"
|
|
1300
|
+
url.gsub! ' ', '+'
|
|
1301
|
+
|
|
1302
|
+
begin
|
|
1303
|
+
response = HTTParty.get(url)
|
|
1304
|
+
Tree << response.body
|
|
1305
|
+
rescue Exception=>e
|
|
1306
|
+
Tree << "- couldn't connect!"
|
|
1307
|
+
end
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
def self.unset_env_vars
|
|
1311
|
+
ENV['prefix'] = nil
|
|
1312
|
+
ENV['txt'] = nil
|
|
1313
|
+
end
|
|
1314
|
+
end
|
|
1315
|
+
|
|
1316
|
+
def require_menu file, options={}
|
|
1317
|
+
if ! options[:ok_if_not_found]
|
|
1318
|
+
raise "File Not Found" if !File.exists?(file)
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
stem = file[/(\w+)\./, 1]
|
|
1322
|
+
|
|
1323
|
+
# As .menu...
|
|
1324
|
+
|
|
1325
|
+
if file =~ /\.menu$/ || options[:force_as] == "menu"
|
|
1326
|
+
Launcher.add stem, :menu_file=>1 do |path|
|
|
1327
|
+
next View.flash("- Xiki couldn't find: #{file}", :times=>5) if ! File.exists?(file)
|
|
1328
|
+
Tree.children File.read(file), Tree.rootless(path)
|
|
1329
|
+
end
|
|
1330
|
+
return
|
|
1331
|
+
end
|
|
1332
|
+
|
|
1333
|
+
# As class, so require and add launcher...
|
|
1334
|
+
|
|
1335
|
+
result = :not_found
|
|
1336
|
+
begin
|
|
1337
|
+
result = Menu.load_if_changed file
|
|
1338
|
+
rescue LoadError => e
|
|
1339
|
+
gem_name = Requirer.extract_gem_from_exception e.to_s
|
|
1340
|
+
Requirer.show "The file #{file} wants to use the '#{gem_name}' gem.\n% sudo gem install #{gem_name}\n\n"
|
|
1341
|
+
rescue Exception=>e
|
|
1342
|
+
txt = CodeTree.draw_exception e
|
|
1343
|
+
Requirer.show "The file #{file} had this exception:\n#{txt}\n\n"
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
return if result == :not_found
|
|
1347
|
+
|
|
1348
|
+
Launcher.add stem if ! Launcher.menus[1][stem]
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
Launcher.init_default_launchers
|