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/keys.rb
ADDED
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
require 'pause_means_space'
|
|
2
|
+
require 'line'
|
|
3
|
+
require 'text_util'
|
|
4
|
+
require 'launcher'
|
|
5
|
+
|
|
6
|
+
# Methods for defining keyboard shortcuts
|
|
7
|
+
class Keys
|
|
8
|
+
|
|
9
|
+
@@key_queue =[] # For defining menus (must be done in reverse)
|
|
10
|
+
|
|
11
|
+
def self.menu
|
|
12
|
+
%`
|
|
13
|
+
- .history/
|
|
14
|
+
- .api/
|
|
15
|
+
> Map C-c C-a
|
|
16
|
+
| Keys.CA { View.insert "foo" }
|
|
17
|
+
|
|
18
|
+
> Map C-d C-h
|
|
19
|
+
| Keys.do_hi { Line << "hey there" }
|
|
20
|
+
|
|
21
|
+
> Map M-x (in shell mode)
|
|
22
|
+
| Keys._X(:shell_mode_map) { View.insert "foooo" }
|
|
23
|
+
|
|
24
|
+
> Get user input
|
|
25
|
+
| - A String
|
|
26
|
+
| - puts Keys.input(:prompt => "Name: ")
|
|
27
|
+
| - Just one char
|
|
28
|
+
| - puts Keys.input :chars=>1
|
|
29
|
+
- docs/
|
|
30
|
+
- Summary/
|
|
31
|
+
> Xiki Shortcuts
|
|
32
|
+
| Xiki has keyboard shortcuts predefined for doing all kinds of things.
|
|
33
|
+
| Each keyboard shortcut has a mnemonic. Check out the "Keys" menu bar
|
|
34
|
+
| menu for a quick look at them.
|
|
35
|
+
|
|
36
|
+
| And Xiki lets you define your own keyboard shortcuts. This line makes
|
|
37
|
+
| Control-e Control-n insert "Steve".
|
|
38
|
+
|
|
39
|
+
| Keys.EN { View << "Steve" }
|
|
40
|
+
|
|
41
|
+
| For more about defining your own keyboard shortcuts see:
|
|
42
|
+
- @keys/api/
|
|
43
|
+
|
|
44
|
+
> Xiki's "type the acronym" approach
|
|
45
|
+
| Each xiki keyboard shortcut has a mnemonic that helps you
|
|
46
|
+
| simultaneously remember what it does and how to type it.
|
|
47
|
+
|
|
48
|
+
| For example, given this mnemonic:
|
|
49
|
+
|
|
50
|
+
| layout_create
|
|
51
|
+
|
|
52
|
+
| you type:
|
|
53
|
+
|
|
54
|
+
| Control-l Control-c (l for "layout" and c for "create")
|
|
55
|
+
|
|
56
|
+
> Reasons for this appoarch
|
|
57
|
+
- More possible shortcuts/
|
|
58
|
+
| The approach of having single character key shortcuts (e.g. Control-a)
|
|
59
|
+
| works nicely for apps that have a small number of shortcuts. But it
|
|
60
|
+
| becomes less elegant when more shortcuts are used (Ctrl-a, Alt-a,
|
|
61
|
+
| Ctrl-Shift-a).
|
|
62
|
+
|
|
63
|
+
| The "type the acronym" approach with just the Control
|
|
64
|
+
| key allows for very a large number of key shortcuts that are less
|
|
65
|
+
| prone to get confused with one another.
|
|
66
|
+
|
|
67
|
+
- Less to remember/
|
|
68
|
+
| A mnemonic clues you into what the keyboard shortcut does and how to type it,
|
|
69
|
+
| so it's all you need to remember. There's no need to separately remember a keyboard shortcut and what it does (a
|
|
70
|
+
| challenging part of most keyboard shortcut schemes having a large number of
|
|
71
|
+
| shortcuts, which xiki attempts to avoid).
|
|
72
|
+
|
|
73
|
+
| Doesn't sound like standard emacs shortcuts? Here's an explanation about
|
|
74
|
+
| how xiki deals with existing emacs shortcuts.
|
|
75
|
+
|
|
76
|
+
- emacs_shortcuts/
|
|
77
|
+
| TODO add stuff about how C-a turns into C-a C-a, etc.
|
|
78
|
+
| Mention how this lets a large number of key shortcuts without interfering
|
|
79
|
+
| with emacs shortcuts.
|
|
80
|
+
| But an admitted downside is it affects 6 existing emacs shortcuts
|
|
81
|
+
| and makes you type them twice.
|
|
82
|
+
| In practice the annoyance caused by this isn't as bad as it initially may seem
|
|
83
|
+
| Consider using to_axis instead of C-a C-a and to_end instead of C-e C-e.
|
|
84
|
+
|
|
85
|
+
> Six categories
|
|
86
|
+
| As you can see by looking at the "Keys" menu in the menu bar, there are
|
|
87
|
+
| six main categories of key shortcuts.
|
|
88
|
+
|
|
89
|
+
- Descriptions of each category/
|
|
90
|
+
- to: jumping to specific points
|
|
91
|
+
- open: opening things
|
|
92
|
+
- layout: views and windows
|
|
93
|
+
- as: remembering things
|
|
94
|
+
- enter: inserting things
|
|
95
|
+
- do: executing things
|
|
96
|
+
|
|
97
|
+
> Examples
|
|
98
|
+
| Here are some of the most commonly used shortcuts in each category.
|
|
99
|
+
| (Double-click a category to see them.)
|
|
100
|
+
|
|
101
|
+
- to/
|
|
102
|
+
| to+highest: Jump to top of file
|
|
103
|
+
| to+lowest: Jump to bottom of file
|
|
104
|
+
| to+axis: Jump to beginning of line
|
|
105
|
+
| to+end: Jump to end of line
|
|
106
|
+
- open/
|
|
107
|
+
| open+bookmark: view a bookmark
|
|
108
|
+
| open+tree: view a tree of a directory
|
|
109
|
+
| open+current: shows currently open files
|
|
110
|
+
| open+edited: shows recently edited files
|
|
111
|
+
| open+history: shows recently viewed files
|
|
112
|
+
| open+menu: opens view that lets you type a menu (type "-" to see all)
|
|
113
|
+
- layout/
|
|
114
|
+
| layout+create: Create a new view
|
|
115
|
+
| layout+hide: Hide this view
|
|
116
|
+
| layout+next: Go to next view
|
|
117
|
+
| layout+previous: Go to previous view
|
|
118
|
+
| layout+kill: Close the current file
|
|
119
|
+
- as/
|
|
120
|
+
| as+clipboard: Copy (after doing Control-space on the other side)
|
|
121
|
+
| as+kill: Cut (after doing Control-space on the other side)
|
|
122
|
+
| as+bookmark: remember this file as a bookmark
|
|
123
|
+
- enter/
|
|
124
|
+
| enter+clipboard: Paste
|
|
125
|
+
- do/
|
|
126
|
+
| do+tree: view an expanded tree of a directory
|
|
127
|
+
- miscellaneous/
|
|
128
|
+
| Control-tab: cycles through files
|
|
129
|
+
|
|
130
|
+
| For all keyboard shortcuts, see where they're key_bindings.rb, where they're
|
|
131
|
+
| defined:
|
|
132
|
+
- @$xiki/key_bindings.rb
|
|
133
|
+
|
|
134
|
+
> Keyboard shortcuts while searching
|
|
135
|
+
| The seventh category, "search" has special behavior. See:
|
|
136
|
+
- @search/docs/
|
|
137
|
+
`
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def self.api
|
|
141
|
+
'
|
|
142
|
+
> Summary
|
|
143
|
+
| Ways to use the Keys class, to define keyboard shortcuts etc. Remember
|
|
144
|
+
| that with xiki shortcuts you hold down the control key and "type the
|
|
145
|
+
| acronym" (the first letter in each word) while holding down the control
|
|
146
|
+
| key.
|
|
147
|
+
|
|
|
148
|
+
> Define keyboard shortcuts
|
|
149
|
+
| Defines the key Control-e Control-y
|
|
150
|
+
|
|
|
151
|
+
| Keys.enter_name { View << "Steve" }
|
|
152
|
+
|
|
|
153
|
+
| Defines the key Control-e Control-y (with no mnemonic)
|
|
154
|
+
|
|
|
155
|
+
| Keys.EN { View << "Steve again" }
|
|
156
|
+
|
|
|
157
|
+
> Where to put them
|
|
158
|
+
| You can put keyboard shortcuts into any file that gets required by xiki.
|
|
159
|
+
| For example, you could create a file like this:
|
|
160
|
+
|
|
|
161
|
+
- @~/my_xiki_stuff/
|
|
162
|
+
- keys.rb
|
|
163
|
+
| # My shortcuts
|
|
164
|
+
| Keys.enter_name { View << "Steve" }
|
|
165
|
+
| Keys.enter_yay { View << "Yay" }
|
|
166
|
+
|
|
|
167
|
+
| Then you could require this file when xiki loads by adding this line:
|
|
168
|
+
|
|
|
169
|
+
- @~/.el4r/
|
|
170
|
+
- init.rb
|
|
171
|
+
| require "~/my_xiki_stuff/keys"
|
|
172
|
+
'
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# Handles Keys.to_foo etc.
|
|
177
|
+
|
|
178
|
+
def self.method_missing(meth, *args, &block)
|
|
179
|
+
|
|
180
|
+
return if ! $el
|
|
181
|
+
|
|
182
|
+
# Accept it if block but no args
|
|
183
|
+
meth = meth.to_s
|
|
184
|
+
|
|
185
|
+
meth_orig = meth.dup
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# Delegate to super unless arg is single symbol
|
|
189
|
+
unless args.size == 0 or (args.size == 1 and args[0].is_a? Symbol)
|
|
190
|
+
return super(meth, *args, &block)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
meth_title = meth.gsub('_', ' ').gsub(/\b\w/) {|s| s.upcase}
|
|
194
|
+
menu, item = meth_title.match(/(.+?) (.+)/)[1..2] if meth_title =~ /. ./
|
|
195
|
+
|
|
196
|
+
# If 1st word is 'isearch', use it as map
|
|
197
|
+
if meth =~ /^search_/
|
|
198
|
+
@@key_queue << ["Search", item]
|
|
199
|
+
meth.sub! /^search_/, ''
|
|
200
|
+
meth = self.words_to_letters meth
|
|
201
|
+
args = [:isearch_mode_map]
|
|
202
|
+
elsif meth =~ /[A-Z]/ # If capital letters
|
|
203
|
+
# Don't convert
|
|
204
|
+
elsif meth =~ /_/ # Add menu item, if more than one word
|
|
205
|
+
|
|
206
|
+
if args.size == 0 # If global keymap
|
|
207
|
+
# Make lisp function
|
|
208
|
+
$el.defun(meth.to_sym, :interactive=>true) do
|
|
209
|
+
block.call
|
|
210
|
+
end
|
|
211
|
+
@@key_queue << [menu, item]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Change 'to_foo' to 'TF' etc
|
|
215
|
+
meth = self.words_to_letters meth
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
keys_raw = self.translate_keys meth # Translate to 'C-t C-f' etc
|
|
219
|
+
|
|
220
|
+
keys = $el.kbd keys_raw # Translate to actual control keys
|
|
221
|
+
|
|
222
|
+
map = :global_map # Default to global keymap
|
|
223
|
+
|
|
224
|
+
# Use keymap if symbol passed as 1st arg
|
|
225
|
+
map = args.shift if args[0] and args[0].class == Symbol
|
|
226
|
+
# If they just passed a string, use it as code
|
|
227
|
+
if args and (args.size == 1) and !block
|
|
228
|
+
self.map_to_eval keys_raw, args[0]
|
|
229
|
+
return
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# # Add menus for key shortcuts - seems kind of pointless in retrospect
|
|
233
|
+
# if map == :global_map && meth_orig =~ /^[a-z]/
|
|
234
|
+
# Launcher.add(meth.downcase, &block)
|
|
235
|
+
# Launcher.add(meth_orig, &block) # if meth_orig =~ /^[a-z]/
|
|
236
|
+
# end
|
|
237
|
+
|
|
238
|
+
# Define key
|
|
239
|
+
begin
|
|
240
|
+
$el.define_key map, keys, &block
|
|
241
|
+
"- key was defined: #{keys_raw}"
|
|
242
|
+
rescue Exception => e
|
|
243
|
+
return if map != :global_map || meth !~ /([A-Z])([A-Z]?)./ # Only global map and 2 control keys
|
|
244
|
+
message = e.message
|
|
245
|
+
prefix = message[/"Key sequence .+? starts with non-prefix key (.+?)"/, 1]
|
|
246
|
+
return if prefix.nil?
|
|
247
|
+
|
|
248
|
+
prefix = $el.kbd(prefix)
|
|
249
|
+
|
|
250
|
+
begin # If it appears to be a prefix key (already defined)
|
|
251
|
+
$el.global_unset_key(prefix)
|
|
252
|
+
$el.define_key map, keys, &block
|
|
253
|
+
|
|
254
|
+
rescue Exception => e
|
|
255
|
+
Ol << "e (inner): #{e.inspect}"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def self.map_to_eval keys_raw, code
|
|
262
|
+
$el.el4r_lisp_eval"
|
|
263
|
+
(global-set-key (kbd \"#{keys_raw}\") (lambda () (interactive)
|
|
264
|
+
(el4r-ruby-eval \"#{code}\" )
|
|
265
|
+
))
|
|
266
|
+
"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def self.translate_keys txt
|
|
270
|
+
l = txt.scan(/_?\w/)
|
|
271
|
+
l.collect! { |b|
|
|
272
|
+
case b
|
|
273
|
+
when /^_([A-Z])/
|
|
274
|
+
"M-" + $1.downcase
|
|
275
|
+
when /^([a-z])$/
|
|
276
|
+
$1
|
|
277
|
+
else
|
|
278
|
+
"C-" + b.downcase
|
|
279
|
+
end
|
|
280
|
+
}
|
|
281
|
+
l.join " "
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def self.set *args, &block
|
|
285
|
+
|
|
286
|
+
# Keys is always first arg
|
|
287
|
+
keys = args.shift
|
|
288
|
+
if args.size > 0 # If 2nd arg, use it
|
|
289
|
+
self.map_to_eval keys, args[0]
|
|
290
|
+
else # Otherwise, use block
|
|
291
|
+
$el.define_key :global_map, $el.kbd(keys), &block
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
#
|
|
296
|
+
# Gets input from user.
|
|
297
|
+
#
|
|
298
|
+
# Sample usages:
|
|
299
|
+
# Keys.input # Terminated by enter
|
|
300
|
+
# Keys.input :chars=>1 # Just one char
|
|
301
|
+
# Keys.input :control=>1 # One char if control
|
|
302
|
+
# Keys.input :timed=>1 # Terminated by pause
|
|
303
|
+
# Keys.input :optional=>1 # Terminated by pause
|
|
304
|
+
# - A pause at the beginning will result in no input (nil)
|
|
305
|
+
#
|
|
306
|
+
def self.input options={}
|
|
307
|
+
|
|
308
|
+
return self.input_with_choices(options) if options[:choices]
|
|
309
|
+
|
|
310
|
+
Cursor.remember :before_input
|
|
311
|
+
Cursor.green
|
|
312
|
+
Cursor.hollow
|
|
313
|
+
|
|
314
|
+
prompt = options[:prompt] || "Input: "
|
|
315
|
+
|
|
316
|
+
# Not completely implemented
|
|
317
|
+
if options[:control]
|
|
318
|
+
prompt = "todo - implement this: "
|
|
319
|
+
|
|
320
|
+
$el.elvar.inhibit_quit = true
|
|
321
|
+
# Maybe use this?
|
|
322
|
+
# Or call self.char?
|
|
323
|
+
# char = $el.char_to_string(Keys.remove_control($el.read_char(prompt))).to_s
|
|
324
|
+
c = read_char(prompt)
|
|
325
|
+
$el.elvar.inhibit_quit = nil
|
|
326
|
+
if c == 7
|
|
327
|
+
Cursor.restore :before_input
|
|
328
|
+
keyboard_quit
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
Cursor.restore :before_input
|
|
332
|
+
return c
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
if options[:chars]
|
|
336
|
+
char = $el.char_to_string(
|
|
337
|
+
self.remove_control($el.read_char(prompt))).to_s
|
|
338
|
+
Cursor.restore :before_input
|
|
339
|
+
return char
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# If simple un-timed input, just get string and return it
|
|
343
|
+
unless options[:timed] || options[:optional]
|
|
344
|
+
Cursor.restore :before_input
|
|
345
|
+
c = $el.read_string(prompt, options[:initial_input])
|
|
346
|
+
return c
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
keys = ""
|
|
350
|
+
|
|
351
|
+
$el.elvar.inhibit_quit = true
|
|
352
|
+
c = nil
|
|
353
|
+
|
|
354
|
+
# If not optional, wait for input initially
|
|
355
|
+
unless options[:optional]
|
|
356
|
+
c = $el.read_char(prompt)
|
|
357
|
+
keys = self.to_letter(c)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
if c == 7
|
|
361
|
+
Cursor.restore :before_input
|
|
362
|
+
$el.elvar.inhibit_quit = nil
|
|
363
|
+
$el.keyboard_quit
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
while(c = $el.read_char("#{prompt}#{keys}", nil, 0.35))
|
|
367
|
+
keys += self.to_letter(c)
|
|
368
|
+
if c == 7
|
|
369
|
+
Cursor.restore :before_input
|
|
370
|
+
$el.elvar.inhibit_quit = nil
|
|
371
|
+
$el.keyboard_quit
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
$el.elvar.inhibit_quit = nil
|
|
375
|
+
Cursor.restore :before_input
|
|
376
|
+
|
|
377
|
+
$el.message ""
|
|
378
|
+
|
|
379
|
+
# If nothing, return nil
|
|
380
|
+
keys == "" ? nil : keys
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# TODO: finish - look at spec
|
|
384
|
+
def self.input_with_choices options
|
|
385
|
+
prompt = options[:prompt] ? "#{options[:prompt]} " : ""
|
|
386
|
+
prompt << options[:choices].map{|i|
|
|
387
|
+
"[#{i.first[/./]}]#{i.first[/.(.+)/,1]}"}.
|
|
388
|
+
join(', ')
|
|
389
|
+
c = Keys.input :chars=>1, :prompt=>prompt
|
|
390
|
+
options[:choices].find{|i| i.first =~ /^#{c}/}[1]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def self.to_letter ch
|
|
394
|
+
return nil if ch.nil?
|
|
395
|
+
if ch < 27
|
|
396
|
+
ch += 96
|
|
397
|
+
|
|
398
|
+
elsif 67108896 <= ch and ch <= 67108921
|
|
399
|
+
ch -= 67108864
|
|
400
|
+
end
|
|
401
|
+
ch.chr
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Converts any control keys in input to normal keys.
|
|
405
|
+
# Example: "\C-x" => "x"
|
|
406
|
+
def self.remove_control ch
|
|
407
|
+
ch += 96 if ch < 27
|
|
408
|
+
ch
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def self.read_char_maybe
|
|
412
|
+
loc = $el.read_char("Optionally type a char:", nil, 0.35)
|
|
413
|
+
$el.message ""
|
|
414
|
+
return if loc.nil?
|
|
415
|
+
|
|
416
|
+
# Convert control chars to the corresponding letters
|
|
417
|
+
loc += 96 if(1 <= loc and loc <= 26)
|
|
418
|
+
loc = self.remove_control loc
|
|
419
|
+
loc
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def self.insert_code
|
|
423
|
+
keys = $el.read_key_sequence("Type some keys, to insert the corresponding code: ")
|
|
424
|
+
|
|
425
|
+
# If C-n or C-p, pretend like they were mapped to xiki functions
|
|
426
|
+
|
|
427
|
+
if keys == "\cn"
|
|
428
|
+
return View << 'Line.next'
|
|
429
|
+
elsif keys == "\cp"
|
|
430
|
+
return View << 'Line.previous'
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
proc = self.proc_from_key keys
|
|
434
|
+
|
|
435
|
+
# If lisp, enter lisp?
|
|
436
|
+
if proc.nil?
|
|
437
|
+
keys = $el.key_binding(keys)
|
|
438
|
+
if keys
|
|
439
|
+
return View.insert($el.prin1_to_string(keys))
|
|
440
|
+
else
|
|
441
|
+
$el.beep
|
|
442
|
+
return View.message("Key is unmapped")
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
code = Code.to_ruby(proc)
|
|
447
|
+
code.gsub! 'proc { ', ''
|
|
448
|
+
code.gsub! ' }', ''
|
|
449
|
+
|
|
450
|
+
code.gsub! '(:blink => (true))', ''
|
|
451
|
+
|
|
452
|
+
View << code
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def self.jump_to_code
|
|
456
|
+
keys = $el.read_key_sequence("Type some keys, to jump to the corresponding code: ")
|
|
457
|
+
proc = self.proc_from_key keys
|
|
458
|
+
if proc.nil?
|
|
459
|
+
$el.beep
|
|
460
|
+
return View.message("Key isn't mapped in Xiki")
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
file, line = Code.location_from_proc proc
|
|
464
|
+
file = "#{XIKI_ROOT}/#{file}" unless file =~ /^\//
|
|
465
|
+
Location.go(file)
|
|
466
|
+
View.to_line line.to_i
|
|
467
|
+
Effects.blink(:what=>:line)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def self.proc_from_key keys
|
|
471
|
+
code = $el.prin1_to_string($el.key_binding(keys))
|
|
472
|
+
# If it is a call to elisp
|
|
473
|
+
id = code[/el4r-ruby-call-proc-by-id.+?([_0-9]+)/, 1]
|
|
474
|
+
return nil if id.nil?
|
|
475
|
+
|
|
476
|
+
ObjectSpace._id2ref(id.to_i)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def self.timed_insert options={}
|
|
480
|
+
prefix = Keys.prefix
|
|
481
|
+
# If prefix of 0, insert in a way that works with macros
|
|
482
|
+
case prefix
|
|
483
|
+
when nil # Do nothing
|
|
484
|
+
when :u # Do pause for space
|
|
485
|
+
PauseMeansSpace.go
|
|
486
|
+
return
|
|
487
|
+
when 0
|
|
488
|
+
View.insert Keys.input(:prompt => "Insert text to insert: ")
|
|
489
|
+
return
|
|
490
|
+
else # If other prefix, insert single char n times
|
|
491
|
+
c = View.read_char("Insert single char to insert #{prefix} times: ").chr
|
|
492
|
+
prefix.times do
|
|
493
|
+
View.insert c
|
|
494
|
+
end
|
|
495
|
+
return
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
Cursor.remember :before_q
|
|
499
|
+
Cursor.green
|
|
500
|
+
|
|
501
|
+
# Get first char and insert
|
|
502
|
+
c = $el.read_char("insert text (pause to exit): ").chr
|
|
503
|
+
inserted = "#{c}"
|
|
504
|
+
|
|
505
|
+
View.insert c
|
|
506
|
+
|
|
507
|
+
# While no pause, insert more chars
|
|
508
|
+
while(c = $el.read_char("insert text (pause to exit): ", nil, 0.36))
|
|
509
|
+
inserted += c.chr
|
|
510
|
+
View.insert c.chr
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
$el.elvar.qinserted = inserted
|
|
514
|
+
$el.message "input ended"
|
|
515
|
+
|
|
516
|
+
Cursor.restore :before_q
|
|
517
|
+
|
|
518
|
+
# Store in hash by first letter for use by enter_yank
|
|
519
|
+
|
|
520
|
+
Clipboard.save_by_first_letter inserted # Store for retrieval with enter_yank
|
|
521
|
+
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
def self.as name
|
|
525
|
+
Clipboard.copy("#{name}")
|
|
526
|
+
Bookmarks.save("$#{name}")
|
|
527
|
+
Bookmarks.save("$_#{name}")
|
|
528
|
+
View.save("#{name}")
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def self.insert_from_q
|
|
532
|
+
($el.elvar.current_prefix_arg || 1).times do
|
|
533
|
+
View.insert($el.elvar.qinserted)
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
def self.prefix_or_0 options={}
|
|
538
|
+
pre = Keys.prefix
|
|
539
|
+
pre.is_a?(Fixnum) ? pre : 0
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
#
|
|
543
|
+
# Set prefix, or append it (space-delimited) if one already there.
|
|
544
|
+
#
|
|
545
|
+
def self.add_prefix new_prefix
|
|
546
|
+
prefix = self.prefix
|
|
547
|
+
|
|
548
|
+
return self.prefix = new_prefix if ! prefix # If none there already, just set it
|
|
549
|
+
|
|
550
|
+
self.prefix = "#{self.prefix} #{new_prefix}"
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def self.prefix options={}
|
|
554
|
+
pre = $el.elvar.current_prefix_arg
|
|
555
|
+
return nil unless pre
|
|
556
|
+
|
|
557
|
+
# Clear prefix if :clear
|
|
558
|
+
$el.elvar.current_prefix_arg = nil if options[:clear]
|
|
559
|
+
str = pre.to_s
|
|
560
|
+
|
|
561
|
+
return :u if str == "u"
|
|
562
|
+
|
|
563
|
+
if str =~ /^\(/
|
|
564
|
+
return :uu if str == "(16)"
|
|
565
|
+
return :uuu if str == "(64)"
|
|
566
|
+
return :u
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
return :- if "#{pre}" == "-"
|
|
570
|
+
return pre
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def self.prefix= to
|
|
574
|
+
$el.elvar.current_prefix_arg = to
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# Whether C-u was held down before this
|
|
578
|
+
def self.prefix_u?
|
|
579
|
+
self.prefix == :u
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
# Whether C-u was held down before this
|
|
583
|
+
# Deprecated
|
|
584
|
+
def self.prefix_u options={}
|
|
585
|
+
result = self.prefix == :u
|
|
586
|
+
self.clear_prefix if options[:clear]
|
|
587
|
+
result
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def self.up? options={}
|
|
591
|
+
self.prefix_u options
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
def self.update? options={}
|
|
595
|
+
# TODO update so prefix can have multiple values, like C-u and "update"
|
|
596
|
+
# for when C-u as+update
|
|
597
|
+
# (space-separated list)?
|
|
598
|
+
# "u update"
|
|
599
|
+
self.prefix == "update"
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def self.delete? options={}
|
|
603
|
+
self.prefix == "delete"
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
def self.open? options={}
|
|
607
|
+
self.prefix == "open"
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
def self.prefix_n options={}
|
|
611
|
+
pre = self.prefix(options)
|
|
612
|
+
return pre if pre.is_a?(Fixnum)
|
|
613
|
+
return $&.to_i if pre.is_a?(String) && pre =~ /\d+/
|
|
614
|
+
nil
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def self.prefix_uu
|
|
618
|
+
self.prefix == :uu
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
def self.clear_prefix
|
|
622
|
+
$el.elvar.current_prefix_arg = nil
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def self.bookmark_as_path options={}
|
|
626
|
+
bm = options[:bm] || Keys.input(:timed=>true, :prompt=>options[:prompt]||"Enter a bookmark: ")
|
|
627
|
+
if bm == " " # If space, return special token
|
|
628
|
+
return :space
|
|
629
|
+
elsif bm == "/" # If slash, return special token
|
|
630
|
+
return :slash
|
|
631
|
+
elsif bm == "x" # If slash, return special token
|
|
632
|
+
return Xiki.dir
|
|
633
|
+
elsif bm == "," # If slash, return special token
|
|
634
|
+
return :comma
|
|
635
|
+
elsif bm =~ /^\.+$/ # If .+ do tree in current dir
|
|
636
|
+
dir = View.dir :force_slash
|
|
637
|
+
(bm.size - 1).times do
|
|
638
|
+
dir.sub! /\/$/, '' # Remove / on end if there
|
|
639
|
+
dir.sub! /[^\/]+$/, '' # Remove dir
|
|
640
|
+
end
|
|
641
|
+
dir.sub! /^$/, '/' # If nothing left, use root (/)
|
|
642
|
+
return dir
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
dir = Bookmarks.expand bm, :just_bookmark=>true
|
|
646
|
+
if dir.nil? # If no dir, return nil
|
|
647
|
+
View.beep "- Bookmark '#{bm}' doesn't exist."
|
|
648
|
+
return :bookmark_doesnt_exist
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
unless options[:include_file]
|
|
652
|
+
dir = Bookmarks.dir_only dir
|
|
653
|
+
dir << "/" unless dir =~ /\/$/
|
|
654
|
+
end
|
|
655
|
+
dir
|
|
656
|
+
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
def self.prefix_times
|
|
660
|
+
prefix = self.prefix
|
|
661
|
+
case prefix
|
|
662
|
+
when nil, :u, :uu, :uuu
|
|
663
|
+
1
|
|
664
|
+
else
|
|
665
|
+
prefix
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
def self.add_menu_items
|
|
670
|
+
@@key_queue.reverse.each do |i|
|
|
671
|
+
Menu.add_item [Menu::ROOT_MENU, i[0]], i[1], "#{i[0].downcase}-#{i[1].downcase.gsub(' ', '-')}"
|
|
672
|
+
end
|
|
673
|
+
@@key_queue = []
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
def self.char
|
|
677
|
+
|
|
678
|
+
$el.elvar.inhibit_quit = true
|
|
679
|
+
ch_initial = $el.read_event.to_s
|
|
680
|
+
$el.elvar.inhibit_quit = nil
|
|
681
|
+
|
|
682
|
+
if ch_initial =~ /^\d+$/ # If a number, assign it to raw
|
|
683
|
+
ch_raw = ch_initial.to_i
|
|
684
|
+
if 134217825 <= ch_raw and ch_raw <= 134217850 # If meta (out of elisp range)
|
|
685
|
+
return ["meta_#{(ch_raw - 134217728).chr}".to_sym, nil]
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
# If char is over the elisp max, try to interpret it as Meta
|
|
689
|
+
ch = $el.char_to_string(ch_raw)
|
|
690
|
+
# Special check for C-. and other sequences
|
|
691
|
+
ch = :control_period if ch_raw == 67108910
|
|
692
|
+
ch = :control_slash if ch_raw == 67108911
|
|
693
|
+
return [ch, ch_raw]
|
|
694
|
+
|
|
695
|
+
elsif ['left', 'right', 'up', 'down', ].member?(ch_initial)
|
|
696
|
+
return [ch_initial.to_sym, 0] # Arbitrary indicator for arrow keys
|
|
697
|
+
|
|
698
|
+
elsif ch_initial == "C-return"
|
|
699
|
+
return [:control_return, 13]
|
|
700
|
+
|
|
701
|
+
elsif ch_initial == "return"
|
|
702
|
+
return [:return, 13]
|
|
703
|
+
|
|
704
|
+
elsif ch_initial == "backspace"
|
|
705
|
+
return [:backspace, 127]
|
|
706
|
+
|
|
707
|
+
elsif ch_initial == "tab"
|
|
708
|
+
return ["\t", 9]
|
|
709
|
+
|
|
710
|
+
else # Probably a mouse event
|
|
711
|
+
return [nil, nil]
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def self.words_to_letters txt
|
|
717
|
+
TextUtil.camel_case(txt).gsub(/[a-z]/, '')
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def self.last nth=1
|
|
721
|
+
$el.el4r_lisp_eval("(elt (recent-keys) (- (length (recent-keys)) #{nth}))").to_s
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def self.before_last
|
|
725
|
+
$el.el4r_lisp_eval("(elt (recent-keys) (- (length (recent-keys)) 2))").to_s
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
def self.history
|
|
729
|
+
$el.view_lossage
|
|
730
|
+
View.flash "- Showed recently-typed keys in other view!", :times=>4
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def self.isearch_prefix shortcut_length=2
|
|
734
|
+
# TODO Make search.stop set Keys.prefix (call .isearch_prefix)
|
|
735
|
+
# Keys.prefix = self.isearch_prefix
|
|
736
|
+
# and don't call .isearch_prefix
|
|
737
|
+
|
|
738
|
+
# What about shortcut_length though? Would we get weird results for search_foo_foo shortcuts? - just try it for now
|
|
739
|
+
|
|
740
|
+
# Return it if character before key shortcut was C-u or C-0 - C-9...
|
|
741
|
+
char = Keys.last(shortcut_length+1).to_i
|
|
742
|
+
return :u if char == 21
|
|
743
|
+
return :- if char == 67108909
|
|
744
|
+
return (char - 67108912) if char >= 67108912 && char <= 67108921
|
|
745
|
+
|
|
746
|
+
nil
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def self.human_readable txt
|
|
750
|
+
txt.split(/[^a-z]/i).map{|o| "Control-#{o[/./].upcase}"}.join(" ")
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
end
|
|
754
|
+
|