sup 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data/History.txt +5 -0
- data/Rakefile +1 -3
- data/bin/sup +8 -5
- data/bin/sup-import +10 -6
- data/doc/TODO +6 -2
- data/doc/UserGuide.txt +188 -30
- data/lib/sup.rb +2 -2
- data/lib/sup/buffer.rb +12 -5
- data/lib/sup/imap.rb +120 -83
- data/lib/sup/index.rb +2 -1
- data/lib/sup/mbox/loader.rb +1 -1
- data/lib/sup/mbox/ssh-file.rb +37 -21
- data/lib/sup/message.rb +14 -10
- data/lib/sup/modes/contact-list-mode.rb +6 -8
- data/lib/sup/modes/inbox-mode.rb +1 -9
- data/lib/sup/modes/label-list-mode.rb +1 -1
- data/lib/sup/modes/label-search-results-mode.rb +1 -5
- data/lib/sup/modes/line-cursor-mode.rb +2 -1
- data/lib/sup/modes/person-search-results-mode.rb +1 -5
- data/lib/sup/modes/reply-mode.rb +7 -2
- data/lib/sup/modes/scroll-mode.rb +5 -3
- data/lib/sup/modes/search-results-mode.rb +1 -5
- data/lib/sup/modes/thread-index-mode.rb +29 -13
- data/lib/sup/modes/thread-view-mode.rb +40 -25
- data/lib/sup/person.rb +1 -1
- data/lib/sup/poll.rb +52 -44
- data/lib/sup/thread.rb +7 -2
- data/lib/sup/util.rb +5 -5
- metadata +2 -2
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -16,12 +16,10 @@ Hoe.new('sup', Redwood::VERSION) do |p|
|
|
16
16
|
end
|
17
17
|
|
18
18
|
rule 'ss?.png' => 'ss?-small.png' do |t|
|
19
|
-
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
21
|
## is there really no way to make a rule for this?
|
24
|
-
WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt)
|
22
|
+
WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt doc/UserGuide.txt)
|
25
23
|
|
26
24
|
SCREENSHOTS = FileList["www/ss?.png"]
|
27
25
|
SCREENSHOTS_SMALL = []
|
data/bin/sup
CHANGED
@@ -100,7 +100,7 @@ begin
|
|
100
100
|
Logger.make_buf
|
101
101
|
|
102
102
|
bm.draw_screen
|
103
|
-
imode.
|
103
|
+
imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread { sleep 1; PollManager.poll } }
|
104
104
|
|
105
105
|
PollManager.start_thread
|
106
106
|
|
@@ -129,7 +129,8 @@ begin
|
|
129
129
|
when :list_buffers
|
130
130
|
bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
|
131
131
|
when :list_contacts
|
132
|
-
bm.spawn_unless_exists("Contact List") { ContactListMode.new }
|
132
|
+
b = bm.spawn_unless_exists("Contact List") { ContactListMode.new }
|
133
|
+
b.mode.load_more b.content_height
|
133
134
|
when :search
|
134
135
|
text = bm.ask :search, "query: "
|
135
136
|
next unless text && text !~ /^\s*$/
|
@@ -140,7 +141,7 @@ begin
|
|
140
141
|
log "built query from #{text.inspect}: #{qobj}"
|
141
142
|
mode = SearchResultsMode.new qobj
|
142
143
|
bm.spawn "search: \"#{short_text}\"", mode
|
143
|
-
mode.
|
144
|
+
mode.load_threads :num => mode.buffer.content_height
|
144
145
|
rescue Ferret::QueryParser::QueryParseException => e
|
145
146
|
bm.flash "Couldn't parse query."
|
146
147
|
end
|
@@ -162,12 +163,14 @@ begin
|
|
162
163
|
when 1
|
163
164
|
m = nil
|
164
165
|
Index.each_id_by_date(:label => :draft) { |mid, builder| m = builder.call }
|
165
|
-
|
166
|
+
r = ResumeMode.new(m)
|
167
|
+
BufferManager.spawn "Edit message", r
|
168
|
+
r.edit
|
166
169
|
else
|
167
170
|
b = BufferManager.spawn_unless_exists(:draft) do
|
168
171
|
mode = LabelSearchResultsMode.new [:draft]
|
169
172
|
end
|
170
|
-
b.mode.
|
173
|
+
b.mode.load_threads :num => b.content_height
|
171
174
|
end
|
172
175
|
when :nothing
|
173
176
|
when :redraw
|
data/bin/sup-import
CHANGED
@@ -49,6 +49,7 @@ the following options:
|
|
49
49
|
--force-read: any messages found will not be marked as new.
|
50
50
|
|
51
51
|
The following options can also be specified:
|
52
|
+
--verbose: print message ids as they're processed
|
52
53
|
--the-usual: import new messages from all usual sources
|
53
54
|
--rebuild: rebuild the index for the specified sources rather than
|
54
55
|
just adding new messages. Useful if the sources
|
@@ -62,6 +63,7 @@ The following options can also be specified:
|
|
62
63
|
EOS
|
63
64
|
exit
|
64
65
|
end
|
66
|
+
#' stupid ruby-mode
|
65
67
|
|
66
68
|
## for sources that require login information, prompt the user for
|
67
69
|
## that. also provide a list of previously-defined login info to
|
@@ -105,6 +107,7 @@ the_usual = ARGV.delete "--the-usual"
|
|
105
107
|
rebuild = ARGV.delete "--rebuild"
|
106
108
|
force_rebuild = ARGV.delete "--force-rebuild"
|
107
109
|
optimize = ARGV.delete "--optimize"
|
110
|
+
verbose = ARGV.delete "--verbose"
|
108
111
|
start_at = # ok really need to use optparse or something now
|
109
112
|
if(i = ARGV.index("--start-at"))
|
110
113
|
raise "start-at requires a numeric argument: #{ARGV[i + 1].inspect}" unless ARGV.length > (i + 1) && ARGV[i + 1] =~ /\d/
|
@@ -167,7 +170,7 @@ begin
|
|
167
170
|
start_offset = nil
|
168
171
|
source.each do |offset, labels|
|
169
172
|
start_offset ||= offset
|
170
|
-
labels -= [:inbox] if force_archive
|
173
|
+
labels -= [:inbox] if force_archive || archive
|
171
174
|
labels -= [:unread] if force_read
|
172
175
|
begin
|
173
176
|
m = Redwood::Message.new :source => source, :source_info => offset, :labels => labels
|
@@ -178,8 +181,9 @@ begin
|
|
178
181
|
found[m.id] = true
|
179
182
|
end
|
180
183
|
|
181
|
-
m.remove_label :unread if m.
|
182
|
-
puts "# message at #{offset}, labels: #{labels * ', '}" unless rebuild
|
184
|
+
m.remove_label :unread if m.source_marked_read? unless force_read
|
185
|
+
puts "# message at #{offset}, labels: #{labels * ', '}" if verbose unless rebuild
|
186
|
+
labels.each { |l| Redwood::LabelManager << l }
|
183
187
|
if (rebuild || force_rebuild) &&
|
184
188
|
(docid, entry = index.load_entry_for_id(m.id)) && entry
|
185
189
|
if force_rebuild || entry[:source_info].to_i != offset
|
@@ -195,9 +199,9 @@ begin
|
|
195
199
|
end
|
196
200
|
if num % 1000 == 0 && num > 0
|
197
201
|
elapsed = Time.now - start
|
198
|
-
pctdone =
|
199
|
-
remaining = (
|
200
|
-
puts "## #{num} (#{
|
202
|
+
pctdone = source.pct_done
|
203
|
+
remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
|
204
|
+
puts "## #{num} (#{pctdone}% done) read; #{elapsed.to_time_s} elapsed; est. #{remaining.to_time_s} remaining"
|
201
205
|
end
|
202
206
|
end
|
203
207
|
puts "loaded #{num} messages" unless num == 0
|
data/doc/TODO
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
batch deletion
|
2
|
+
on startup, multi-threadedly call #connect on all sources
|
1
3
|
support for message-content modules such as ruby-talk:XXXXX detection
|
2
4
|
use Net::SMTP
|
3
5
|
search for other messages from author in thread-view-mode
|
@@ -13,9 +15,11 @@ editing of arbitrary messages
|
|
13
15
|
annotations on messages
|
14
16
|
gmail
|
15
17
|
pop
|
16
|
-
move sup-import argument handling to getopt
|
17
|
-
mark individual messages as spam in thread-view-mode
|
18
|
+
move sup-import argument handling to getopt
|
19
|
+
be able to mark individual messages as spam in thread-view-mode
|
18
20
|
|
21
|
+
x fix snippet repetitions with small snippets
|
22
|
+
x fix next and previous in thread-view-mode with <unreceived messages>
|
19
23
|
x move sup-import username/password prompts to highline
|
20
24
|
x support different remote servers per user account
|
21
25
|
x 'R' to quick-resume most recent draft
|
data/doc/UserGuide.txt
CHANGED
@@ -1,54 +1,212 @@
|
|
1
1
|
Welcome to Sup! Here's how to actually use it.
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
Sup needs to have some "sources" from which to load messages.
|
3
|
+
First, try running 'sup'. Assuming this is your first time, you'll be
|
4
|
+
confronted with a mostly blank screen, and a notice at the bottom that
|
5
|
+
you have no new messages. That's because Sup doesn't have any messages
|
6
|
+
in its index yet, and has no idea where to look for them anyways.
|
8
7
|
|
9
8
|
If you want to play around a little at this point, you can press 'b'
|
10
9
|
to cycle between buffers and 'x' to kill a buffer. There's probably
|
11
10
|
not too much interesting there, but there's a log buffer with some
|
12
11
|
cryptic messages. You can also press '?' at any point to get a list of
|
13
12
|
keyboard commands, but in the absense of any email, these will be
|
14
|
-
|
13
|
+
mostly useless. When you're bored, press 'q' to quit.
|
15
14
|
|
16
|
-
|
17
|
-
|
15
|
+
We need to add some messages to Sup. In order for Sup to know about a
|
16
|
+
message, it must be in the index. In order for Sup to load a message
|
17
|
+
into the index, it must know about the "source" in which it
|
18
|
+
resides. Sup stores all information necessary for search, and all
|
19
|
+
state we have about a message, in the index, but doesn't duplicate the
|
20
|
+
actual contents of the message itself. So when you search for messages
|
21
|
+
or view your inbox, Sup just talks to the index (stored locally on
|
22
|
+
disk), but when you view a message, Sup must request it from the
|
23
|
+
source.
|
24
|
+
|
25
|
+
So let's tell Sup about some sources. Run 'sup-import' with a URI
|
26
|
+
pointing to an email source. The URI should be of the form:
|
18
27
|
- mbox://path/to/a/filename, for an mbox file on disk. (You can also
|
19
28
|
just provide the filename).
|
20
29
|
- imap://imap.server/folder or imaps://secure.imap.server/folder for
|
21
|
-
an IMAP
|
30
|
+
an IMAP folder. (Leave the folder blank for INBOX.)
|
22
31
|
- mbox+ssh://remote.machine/path/to/a/filename for a remote mbox file.
|
23
32
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
Before you actually import messages, you need to decide whether you
|
34
|
+
want them to be archived or not. An archived message will not show up
|
35
|
+
in your inbox. (Your inbox in Sup is, by definition, the set of all
|
36
|
+
all non-archived messages). If you specify --force-archive, messages
|
37
|
+
imported at *this* time will be archived, but new messages will go to
|
38
|
+
your inbox. If you specify --archive, messages imported at *any* time
|
39
|
+
will be automatically archived. (This is useful for sources that
|
40
|
+
contain high-traffic mailing lists that you don't want "polluting"
|
41
|
+
your inbox.)
|
42
|
+
|
43
|
+
Typically you'll want to specify --archive for every source you import
|
44
|
+
except your actual inbox. You can also force all messages to be marked
|
45
|
+
as read; run sup-import --help for details. The default is to preserve
|
46
|
+
the read/unread status from the source.
|
30
47
|
|
31
|
-
|
32
|
-
prompt you
|
33
|
-
|
34
|
-
|
35
|
-
|
48
|
+
Now run sup-import to add the source. If it requires a username and
|
49
|
+
password for the source, it will prompt you. Either way, it will add
|
50
|
+
the sources to Sup, and immediately start loading messages from them
|
51
|
+
into the index. Depending on the size of the source, this may take a
|
52
|
+
while. Don't panic! It's a one-time process.
|
36
53
|
|
37
54
|
Now, before we run 'sup' again, take a moment to edit your
|
38
55
|
~/.sup/config.yaml file. Replace "Your Name Here" with your name,
|
39
56
|
"your.email.here@domain.tld" with your email address, and fill in your
|
40
57
|
.signature file if you choose. You can also set the default editor.
|
41
58
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
you
|
47
|
-
|
59
|
+
We're finally ready to run 'sup'. You should see the most recent
|
60
|
+
loaded messages appear in your inbox. Congratulations, you've got Sup
|
61
|
+
working!
|
62
|
+
|
63
|
+
If you're coming from the world of traditional email, there are a
|
64
|
+
couple differences you should be aware of at this point. First, Sup
|
65
|
+
does not use folders. Instead, you organize and find messages by a
|
66
|
+
combination of search and labels (knowns as 'tags' everywhere else in
|
67
|
+
the world). I like to say that 95% of the functionality of folders is
|
68
|
+
superceded by a quick, easy-to-access, and powerful search mechanism,
|
69
|
+
and the other 5% by labels. (The Sup statement of philosophy has a
|
70
|
+
little more on this.)
|
71
|
+
|
72
|
+
Search and labels are an integral part of Sup because in Sup, rather
|
73
|
+
than viewing the contents of a folder, you view the results of a
|
74
|
+
search. I mentioned above that your inbox is, by definition, the set
|
75
|
+
of all messages that aren't archived. This means that your inbox is,
|
76
|
+
in fact, the result of the search for "all messages without the label
|
77
|
+
'archive'". It's actually slightly more complicated---we omit killed,
|
78
|
+
deleted and spam messages as well.
|
79
|
+
|
80
|
+
So you could replicate the folder paradigm easily under this scheme,
|
81
|
+
by giving each message exactly one label and only viewing the results
|
82
|
+
of simple searches for those labels. But you'd quickly find out that
|
83
|
+
life can be easier than that if you just trust the search engine, and
|
84
|
+
use labels judiciously for things that are too hard to find with
|
85
|
+
search.
|
86
|
+
|
87
|
+
But enough chit-chat! Let's take a look at your inbox. You'll see that
|
88
|
+
Sup groups messages together into threads: each line in the inbox is a
|
89
|
+
thread, and the number in parentheses is the number of messages in
|
90
|
+
that thread. (If there's no number in parens, it means there's just
|
91
|
+
one message.) In Sup, you rarely operate on an individual message. The
|
92
|
+
idea is that you rarely want to operate on a message independent of
|
93
|
+
its context; you typically want to view, archive, kill, or label all
|
94
|
+
the messages in a thread at one time.
|
95
|
+
|
96
|
+
Use the up and down arrows to highlight a thread. ('j' and 'k' do the
|
97
|
+
same thing, and 'J' and 'K' will scroll the whole window. Even the
|
98
|
+
left and right arrow keys work!) By default, Sup only loads as many
|
99
|
+
threads as it takes to fill the window; if you'd like to load more,
|
100
|
+
press 'M'. You can hit tab to cycle between only threads with new
|
101
|
+
messages.
|
102
|
+
|
103
|
+
Highlight a thread and press enter to view it. You'll notice that all
|
104
|
+
messages in the thread are displayed together, layed out graphically
|
105
|
+
by their relationship to each other (replies are nested under
|
106
|
+
parents). By default, only the new messages in a thread are expanded,
|
107
|
+
and the others are hidden. You can toggle an individual message's
|
108
|
+
state by highlighting a green line and pressing enter. You can use 'E'
|
109
|
+
to expand or collapse all messages or 'N' to expand only the new
|
110
|
+
messages. You'll also notice that Sup hides quoted text and
|
111
|
+
signatures. If you highlight a particular hidden chunk, you can press
|
112
|
+
enter to expand it, or you can press 'o' to toggle every hidden chunk
|
113
|
+
in a particular message. (Don't worry about remembering all these
|
114
|
+
things---you can hit '?' to see the full list of keyboard commands at
|
115
|
+
any point.)
|
116
|
+
|
117
|
+
A few other useful commands while viewing a thread. Press 'd' to
|
118
|
+
toggle a detailed header fpr a message. If you've scrolled too far to
|
119
|
+
the right, press '[' to jump all the way to the left. Finally, you can
|
120
|
+
press 'n' and 'p' to jump forward and backward between open
|
121
|
+
messages. (I find that very useful!)
|
122
|
+
|
123
|
+
Now press 'x' to kill the thread view buffer. You should see the inbox
|
124
|
+
again. If you don't, you can cycle through the buffers by pressing
|
125
|
+
'b', or you can press 'A' to see a list of all buffers and simply
|
126
|
+
select the inbox.
|
127
|
+
|
128
|
+
There are many operations you can perform on threads beyond viewing
|
129
|
+
them. To archive a thread, press 'a'. The thread will disappear from
|
130
|
+
your inbox, but will still appear in search results. If someone
|
131
|
+
replies an archived thread, it will reappear in your inbox. To kill a
|
132
|
+
thread, press '&'. Killed threads will never come back to your inbox,
|
133
|
+
even if people reply, but will still be searchable. (This is useful
|
134
|
+
for those interminable threads that you really have no interest in,
|
135
|
+
but which seem to pop up on every mailing list.)
|
136
|
+
|
137
|
+
If a thread is spam, press 'S'. It will disappear and won't come
|
138
|
+
back. It won't even appear in search results (unless you explicitly
|
139
|
+
search for spam.)
|
140
|
+
|
141
|
+
You can also star a thread by pressing '*'. Starred threads are
|
142
|
+
displayed with a little yellow asterix next to them, but otherwise
|
143
|
+
have no special semantics. (But you can also search for them
|
144
|
+
easily---we'll see how in a moment).
|
145
|
+
|
146
|
+
To edit the labels for (all the messages in) a thread, press 'l'. Type
|
147
|
+
in the labels as a sequence of space-separated words. To cancel the
|
148
|
+
input, press Ctrl-G.
|
149
|
+
|
150
|
+
Many of these operations can be applied to a group of threads. Press
|
151
|
+
't' to tag a thread. Tag a couple, then press ';' to apply the next
|
152
|
+
command to the set of threads. ';t', of course, will untag all tagged
|
153
|
+
messages.
|
154
|
+
|
155
|
+
Ok, let's try using labels and search. Press 'L' to bring up a list of
|
156
|
+
all the labels you've ever used, along with some special labels
|
157
|
+
(Draft, Starred, Sent, Spam, etc.). Highlight a label and press enter
|
158
|
+
to view all the messages with that label.
|
159
|
+
|
160
|
+
What you just did was actually a specific search. For a general
|
161
|
+
search, press "/". Now type in your query (again, Ctrl-G to cancel at
|
162
|
+
any point.) You can just type in arbitrary text, which will be matched
|
163
|
+
on a per-word basis against the bodies of all email in the index, or
|
164
|
+
you can make use of the full Ferret query syntax:
|
165
|
+
|
166
|
+
- Phrasal queries using double-quotes, e.g.: "three contiguous words"
|
167
|
+
- Queries against a particular field using <field name>:<query>,
|
168
|
+
e.g.: label:ruby-talk, or from:matz@ruby-lang.org. (Fields include:
|
169
|
+
body, from, to, and subject.)
|
170
|
+
- Force occurrence and non-occurrence using + and -, e.g. +label:spam,
|
171
|
+
or -body:"hot soup"
|
172
|
+
|
173
|
+
You can combine those all together. For example:
|
174
|
+
+label:ruby-talk +subject:\[ANN\] -rails
|
175
|
+
|
176
|
+
Play around with the search, and see the Ferret documentation for
|
177
|
+
details on more sophisticated queries (date ranges, "within n words",
|
178
|
+
etc.)
|
179
|
+
|
180
|
+
At this point, you're well on your way to figuring out all the cool
|
181
|
+
things Sup can do. By repeated applications of the '?' key, see if you
|
182
|
+
can figure out how to:
|
183
|
+
- List some recent contacts
|
184
|
+
- Easily search for all mail from a recent contact
|
185
|
+
- Easily search for all mail from several recent contacts!
|
186
|
+
- Add someone to your address book
|
187
|
+
- Postpone a message (i.e., save a draft)
|
188
|
+
- Quickly re-edit a just-saved draft message
|
189
|
+
- View the raw header of a message
|
190
|
+
- Star an individual message, not just a thread
|
191
|
+
|
192
|
+
There's one last thing to be aware of when using Sup: how it interacts
|
193
|
+
with other email programs. Sup stores data about messages in the
|
194
|
+
index---information necessary for searching, and message state---but
|
195
|
+
doesn't duplicate the message contents themselves. The messages remain
|
196
|
+
on the source. If the index and the source every fall out of sync,
|
197
|
+
e.g. due to another email client modifying the source, then Sup will
|
198
|
+
be unable to operate on that source.
|
48
199
|
|
49
|
-
|
50
|
-
|
200
|
+
For example, for mbox files, Sup stores a byte offset into the file
|
201
|
+
for each message. If a message deleted from that file by another
|
202
|
+
client, or even marked as read (yeah, mbox sucks), all succeeding
|
203
|
+
offsets will be wrong.
|
51
204
|
|
52
|
-
|
205
|
+
That's the bad news. The good news is that Sup is fairly good at being
|
206
|
+
able to detect this type of situation, and fixing it is just a matter
|
207
|
+
of running sup-import --rebuild on the source. Sup will even tell you
|
208
|
+
how to invoke sup-import when it detects a problem. This is a
|
209
|
+
complication you will almost certainly run in to if you use both Sup
|
210
|
+
and another MUA on the same source, so it's good to be aware of it.
|
53
211
|
|
54
|
-
|
212
|
+
Have fun, and let me know if you have any problems. --William
|
data/lib/sup.rb
CHANGED
@@ -13,7 +13,7 @@ class Object
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module Redwood
|
16
|
-
VERSION = "0.0.
|
16
|
+
VERSION = "0.0.5"
|
17
17
|
|
18
18
|
BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
|
19
19
|
CONFIG_FN = File.join(BASE_DIR, "config.yaml")
|
@@ -105,7 +105,7 @@ else
|
|
105
105
|
:email => "your.email.here@domain.tld",
|
106
106
|
:alternates => [],
|
107
107
|
:sendmail => "/usr/sbin/sendmail -oem -ti",
|
108
|
-
:
|
108
|
+
:signature => File.join(ENV["HOME"], ".signature")
|
109
109
|
}
|
110
110
|
},
|
111
111
|
:editor => ENV["EDITOR"] || "/usr/bin/vi",
|
data/lib/sup/buffer.rb
CHANGED
@@ -217,7 +217,6 @@ class BufferManager
|
|
217
217
|
if true
|
218
218
|
buf = @buffers.last
|
219
219
|
buf.resize Ncurses.rows - minibuf_lines, Ncurses.cols
|
220
|
-
File.open("asdf.txt", "a") { |f| f.puts "dirty #@dirty, (re)drawing #{buf.mode.name}" }
|
221
220
|
@dirty ? buf.draw : buf.redraw
|
222
221
|
end
|
223
222
|
|
@@ -233,7 +232,6 @@ class BufferManager
|
|
233
232
|
## the mode is expensive, as it often is.
|
234
233
|
def spawn_unless_exists title, opts={}
|
235
234
|
if @name_map.member? title
|
236
|
-
Redwood::log "buffer '#{title}' already exists, raising to front"
|
237
235
|
raise_to_front @name_map[title] unless opts[:hidden]
|
238
236
|
else
|
239
237
|
mode = yield
|
@@ -292,7 +290,10 @@ class BufferManager
|
|
292
290
|
end
|
293
291
|
end
|
294
292
|
|
293
|
+
## not really thread safe.
|
295
294
|
def ask domain, question, default=nil
|
295
|
+
raise "impossible!" if @asking
|
296
|
+
|
296
297
|
@textfields[domain] ||= TextField.new Ncurses.stdscr, Ncurses.rows - 1, 0, Ncurses.cols
|
297
298
|
tf = @textfields[domain]
|
298
299
|
|
@@ -310,7 +311,10 @@ class BufferManager
|
|
310
311
|
ret = nil
|
311
312
|
tf.position_cursor
|
312
313
|
Ncurses.sync { Ncurses.refresh }
|
314
|
+
|
315
|
+
@asking = true
|
313
316
|
while tf.handle_input(Ncurses.nonblocking_getch); end
|
317
|
+
@asking = false
|
314
318
|
|
315
319
|
ret = tf.value
|
316
320
|
Ncurses.sync { tf.deactivate }
|
@@ -369,7 +373,9 @@ class BufferManager
|
|
369
373
|
|
370
374
|
def minibuf_lines
|
371
375
|
@minibuf_mutex.synchronize do
|
372
|
-
[(@flash ? 1 : 0) +
|
376
|
+
[(@flash ? 1 : 0) +
|
377
|
+
(@asking ? 1 : 0) +
|
378
|
+
@minibuf_stack.compact.size, 1].max
|
373
379
|
end
|
374
380
|
end
|
375
381
|
|
@@ -383,8 +389,9 @@ class BufferManager
|
|
383
389
|
|
384
390
|
Ncurses.mutex.lock unless opts[:sync] == false
|
385
391
|
Ncurses.attrset Colormap.color_for(:none)
|
392
|
+
adj = @asking ? 2 : 1
|
386
393
|
m.each_with_index do |s, i|
|
387
|
-
Ncurses.mvaddstr Ncurses.rows - i -
|
394
|
+
Ncurses.mvaddstr Ncurses.rows - i - adj, 0, s + (" " * [Ncurses.cols - s.length, 0].max)
|
388
395
|
end
|
389
396
|
Ncurses.refresh if opts[:refresh]
|
390
397
|
Ncurses.mutex.unlock unless opts[:sync] == false
|
@@ -406,7 +413,7 @@ class BufferManager
|
|
406
413
|
|
407
414
|
if block_given?
|
408
415
|
begin
|
409
|
-
yield
|
416
|
+
yield id
|
410
417
|
ensure
|
411
418
|
clear id
|
412
419
|
end
|