sup 0.1 → 0.2
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 +9 -0
- data/Manifest.txt +5 -1
- data/Rakefile +2 -1
- data/bin/sup +27 -10
- data/bin/sup-add +2 -1
- data/bin/sup-sync-back +51 -23
- data/doc/FAQ.txt +29 -37
- data/doc/Hooks.txt +38 -0
- data/doc/{UserGuide.txt → NewUserGuide.txt} +27 -21
- data/doc/TODO +91 -57
- data/lib/sup.rb +17 -1
- data/lib/sup/buffer.rb +80 -16
- data/lib/sup/colormap.rb +0 -2
- data/lib/sup/contact.rb +3 -2
- data/lib/sup/crypto.rb +110 -0
- data/lib/sup/draft.rb +2 -6
- data/lib/sup/hook.rb +131 -0
- data/lib/sup/imap.rb +27 -16
- data/lib/sup/index.rb +38 -14
- data/lib/sup/keymap.rb +0 -2
- data/lib/sup/label.rb +30 -9
- data/lib/sup/logger.rb +12 -1
- data/lib/sup/maildir.rb +48 -3
- data/lib/sup/mbox.rb +1 -1
- data/lib/sup/mbox/loader.rb +22 -12
- data/lib/sup/mbox/ssh-loader.rb +1 -1
- data/lib/sup/message-chunks.rb +198 -0
- data/lib/sup/message.rb +154 -115
- data/lib/sup/modes/compose-mode.rb +18 -0
- data/lib/sup/modes/contact-list-mode.rb +1 -1
- data/lib/sup/modes/edit-message-mode.rb +112 -31
- data/lib/sup/modes/file-browser-mode.rb +1 -1
- data/lib/sup/modes/inbox-mode.rb +1 -1
- data/lib/sup/modes/label-list-mode.rb +8 -6
- data/lib/sup/modes/label-search-results-mode.rb +4 -1
- data/lib/sup/modes/log-mode.rb +1 -1
- data/lib/sup/modes/reply-mode.rb +18 -16
- data/lib/sup/modes/search-results-mode.rb +1 -1
- data/lib/sup/modes/thread-index-mode.rb +61 -33
- data/lib/sup/modes/thread-view-mode.rb +111 -102
- data/lib/sup/person.rb +5 -1
- data/lib/sup/poll.rb +36 -7
- data/lib/sup/sent.rb +1 -0
- data/lib/sup/source.rb +7 -3
- data/lib/sup/textfield.rb +48 -34
- data/lib/sup/thread.rb +9 -5
- data/lib/sup/util.rb +16 -22
- metadata +7 -3
data/lib/sup/sent.rb
CHANGED
data/lib/sup/source.rb
CHANGED
@@ -31,7 +31,7 @@ class Source
|
|
31
31
|
## - load_header offset
|
32
32
|
## - load_message offset
|
33
33
|
## - raw_header offset
|
34
|
-
## -
|
34
|
+
## - raw_message offset
|
35
35
|
## - check
|
36
36
|
## - next (or each, if you prefer): should return a message and an
|
37
37
|
## array of labels.
|
@@ -77,8 +77,8 @@ class Source
|
|
77
77
|
def seek_to! o; self.cur_offset = o; end
|
78
78
|
def reset!; seek_to! start_offset; end
|
79
79
|
def == o; o.uri == uri; end
|
80
|
-
def done?; (self.cur_offset ||= start_offset) >= end_offset; end
|
81
|
-
def is_source_for? uri;
|
80
|
+
def done?; start_offset.nil? || (self.cur_offset ||= start_offset) >= end_offset; end
|
81
|
+
def is_source_for? uri; uri == @uri; end
|
82
82
|
|
83
83
|
## check should throw a FatalSourceError or an OutOfSyncSourcError
|
84
84
|
## if it can detect a problem. it is called when the sup starts up
|
@@ -96,6 +96,10 @@ class Source
|
|
96
96
|
|
97
97
|
protected
|
98
98
|
|
99
|
+
def Source.expand_filesystem_uri uri
|
100
|
+
uri.gsub "~", File.expand_path("~")
|
101
|
+
end
|
102
|
+
|
99
103
|
def cur_offset= o
|
100
104
|
@cur_offset = o
|
101
105
|
@dirty = true
|
data/lib/sup/textfield.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
require 'curses'
|
2
|
-
|
3
1
|
module Redwood
|
4
2
|
|
5
3
|
## a fully-functional text field supporting completions, expansions,
|
6
4
|
## history--everything!
|
5
|
+
##
|
6
|
+
## writing this fucking sucked. if you thought ncurses was some 1970s
|
7
|
+
## before-people-knew-how-to-program bullshit, wait till you see
|
8
|
+
## ncurses forms.
|
7
9
|
##
|
8
|
-
## completion is done emacs-style, and mostly
|
9
|
-
## support, as we merely signal the existence of a
|
10
|
-
## completions to show (#new_completions?) or that the
|
11
|
-
## of completions should be rolled if they're too large
|
12
|
-
## screen (#roll_completions?).
|
10
|
+
## completion comments: completion is done emacs-style, and mostly
|
11
|
+
## depends on outside support, as we merely signal the existence of a
|
12
|
+
## new set of completions to show (#new_completions?) or that the
|
13
|
+
## current list of completions should be rolled if they're too large
|
14
|
+
## to fill the screen (#roll_completions?).
|
13
15
|
##
|
14
16
|
## in sup, completion support is implemented through BufferManager#ask
|
15
17
|
## and CompletionMode.
|
@@ -27,22 +29,17 @@ class TextField
|
|
27
29
|
bool_reader :new_completions, :roll_completions
|
28
30
|
attr_reader :completions
|
29
31
|
|
30
|
-
|
31
|
-
## clean up all the ncurses cruft. before @value is set, we can
|
32
|
-
## get the current value from ncurses.
|
33
|
-
def value; @field ? get_cur_value : @value end
|
32
|
+
def value; @value || get_cursed_value end
|
34
33
|
|
35
34
|
def activate question, default=nil, &block
|
36
35
|
@question = question
|
37
|
-
@value = nil
|
38
36
|
@completion_block = block
|
39
37
|
@field = Ncurses::Form.new_field 1, @width - question.length,
|
40
38
|
@y, @x + question.length, 0, 0
|
41
39
|
@form = Ncurses::Form.new_form [@field]
|
42
|
-
|
43
|
-
@history[@i = @history.size] = default || ""
|
40
|
+
@value = default
|
44
41
|
Ncurses::Form.post_form @form
|
45
|
-
|
42
|
+
set_cursed_value default if default
|
46
43
|
end
|
47
44
|
|
48
45
|
def position_cursor
|
@@ -50,7 +47,7 @@ class TextField
|
|
50
47
|
@w.mvaddstr @y, 0, @question
|
51
48
|
Ncurses.curs_set 1
|
52
49
|
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
|
53
|
-
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_NEXT_CHAR if @
|
50
|
+
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_NEXT_CHAR if @value && @value =~ / $/ # fucking RETARDED!!!!
|
54
51
|
end
|
55
52
|
|
56
53
|
def deactivate
|
@@ -66,20 +63,21 @@ class TextField
|
|
66
63
|
## short-circuit exit paths
|
67
64
|
case c
|
68
65
|
when Ncurses::KEY_ENTER # submit!
|
69
|
-
@value =
|
66
|
+
@value = get_cursed_value
|
67
|
+
@history.push @value
|
70
68
|
return false
|
71
69
|
when Ncurses::KEY_CANCEL # cancel
|
72
|
-
@history.delete_at @i
|
73
|
-
@i = @history.empty? ? nil : (@i - 1) % @history.size
|
74
70
|
@value = nil
|
75
71
|
return false
|
76
72
|
when Ncurses::KEY_TAB # completion
|
77
73
|
return true unless @completion_block
|
78
74
|
if @completions.empty?
|
79
|
-
v =
|
75
|
+
v = get_cursed_value
|
80
76
|
c = @completion_block.call v
|
81
77
|
if c.size > 0
|
82
|
-
|
78
|
+
@value = c.map { |full, short| full }.shared_prefix(true)
|
79
|
+
set_cursed_value @value
|
80
|
+
position_cursor
|
83
81
|
end
|
84
82
|
if c.size > 1
|
85
83
|
@completions = c
|
@@ -94,6 +92,7 @@ class TextField
|
|
94
92
|
end
|
95
93
|
|
96
94
|
reset_completion_state
|
95
|
+
@value = nil
|
97
96
|
|
98
97
|
d =
|
99
98
|
case c
|
@@ -103,18 +102,24 @@ class TextField
|
|
103
102
|
Ncurses::Form::REQ_NEXT_CHAR
|
104
103
|
when Ncurses::KEY_BACKSPACE
|
105
104
|
Ncurses::Form::REQ_DEL_PREV
|
106
|
-
when
|
105
|
+
when 1 #ctrl-a
|
107
106
|
Ncurses::Form::REQ_BEG_FIELD
|
108
|
-
when
|
107
|
+
when 5 #ctrl-e
|
109
108
|
Ncurses::Form::REQ_END_FIELD
|
109
|
+
when 11 # ctrl-k
|
110
|
+
Ncurses::Form::REQ_CLR_EOF
|
110
111
|
when Ncurses::KEY_UP
|
111
|
-
@
|
112
|
+
@i ||= @history.size
|
113
|
+
@history[@i] = get_cursed_value
|
112
114
|
@i = (@i - 1) % @history.size
|
113
|
-
|
115
|
+
@value = @history[@i]
|
116
|
+
set_cursed_value @value
|
114
117
|
when Ncurses::KEY_DOWN
|
115
|
-
@
|
118
|
+
@i ||= @history.size
|
119
|
+
@history[@i] = get_cursed_value
|
116
120
|
@i = (@i + 1) % @history.size
|
117
|
-
|
121
|
+
@value = @history[@i]
|
122
|
+
set_cursed_value @value
|
118
123
|
else
|
119
124
|
c
|
120
125
|
end
|
@@ -131,16 +136,25 @@ private
|
|
131
136
|
end
|
132
137
|
|
133
138
|
## ncurses inanity wrapper
|
134
|
-
|
139
|
+
##
|
140
|
+
## DO NOT READ THIS CODE. YOU WILL GO MAD.
|
141
|
+
def get_cursed_value
|
142
|
+
return nil unless @field
|
143
|
+
|
144
|
+
x = Ncurses.curx
|
135
145
|
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_VALIDATION
|
136
|
-
@field.field_buffer(0).gsub(/^\s+|\s+$/, "")
|
146
|
+
v = @field.field_buffer(0).gsub(/^\s+|\s+$/, "")
|
147
|
+
|
148
|
+
## cursor <= end of text
|
149
|
+
if x - @question.length - v.length <= 0
|
150
|
+
v
|
151
|
+
else # trailing spaces
|
152
|
+
v + (" " * (x - @question.length - v.length))
|
153
|
+
end
|
137
154
|
end
|
138
|
-
|
139
|
-
|
140
|
-
def set_cur_value v
|
155
|
+
|
156
|
+
def set_cursed_value v
|
141
157
|
@field.set_field_buffer 0, v
|
142
|
-
Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
|
143
158
|
end
|
144
|
-
|
145
159
|
end
|
146
160
|
end
|
data/lib/sup/thread.rb
CHANGED
@@ -54,7 +54,7 @@ class Thread
|
|
54
54
|
|
55
55
|
## yields each message, its depth, and its parent. the message yield
|
56
56
|
## parameter can be a Message object, or :fake_root, or nil (no
|
57
|
-
## message found but the presence of one
|
57
|
+
## message found but the presence of one deduced from other
|
58
58
|
## messages).
|
59
59
|
def each fake_root=false
|
60
60
|
adj = 0
|
@@ -85,7 +85,10 @@ class Thread
|
|
85
85
|
def first; each { |m, *o| return m if m }; nil; end
|
86
86
|
def dirty?; any? { |m, *o| m && m.dirty? }; end
|
87
87
|
def date; map { |m, *o| m.date if m }.compact.max; end
|
88
|
-
def snippet
|
88
|
+
def snippet
|
89
|
+
last_m, last_stuff = select { |m, *o| m && m.snippet && !m.snippet.empty? }.sort_by { |m, *o| m.date }.last
|
90
|
+
last_m ? last_m.snippet : ""
|
91
|
+
end
|
89
92
|
def authors; map { |m, *o| m.from if m }.compact.uniq; end
|
90
93
|
|
91
94
|
def apply_label t; each { |m, *o| m && m.add_label(t) }; end
|
@@ -303,18 +306,19 @@ class ThreadSet
|
|
303
306
|
next if contains_id? mid
|
304
307
|
|
305
308
|
m = builder.call
|
306
|
-
|
307
|
-
load_thread_for_message m, :load_killed => opts[:load_killed]
|
309
|
+
load_thread_for_message m, :skip_killed => opts[:skip_killed], :load_deleted => opts[:load_deleted], :load_spam => opts[:load_spam]
|
308
310
|
yield size if block_given?
|
309
311
|
end
|
310
312
|
end
|
311
313
|
|
312
314
|
## loads in all messages needed to thread m
|
315
|
+
## may do nothing if m's thread is killed
|
313
316
|
def load_thread_for_message m, opts={}
|
314
|
-
@index.each_message_in_thread_for m, opts
|
317
|
+
good = @index.each_message_in_thread_for m, opts do |mid, builder|
|
315
318
|
next if contains_id? mid
|
316
319
|
add_message builder.call
|
317
320
|
end
|
321
|
+
add_message m if good
|
318
322
|
end
|
319
323
|
|
320
324
|
## merges in a pre-loaded thread
|
data/lib/sup/util.rb
CHANGED
@@ -63,13 +63,13 @@ module RMail
|
|
63
63
|
class EncodingUnsupportedError < StandardError; end
|
64
64
|
|
65
65
|
class Message
|
66
|
-
def
|
66
|
+
def add_file_attachment fn
|
67
67
|
bfn = File.basename fn
|
68
68
|
a = Message.new
|
69
69
|
t = MIME::Types.type_for(bfn).first || MIME::Types.type_for("exe").first
|
70
70
|
|
71
|
-
a.header.add "Content-Disposition", "attachment; filename=#{bfn}"
|
72
|
-
a.header.add "Content-Type", "#{t.content_type}; name=#{bfn}"
|
71
|
+
a.header.add "Content-Disposition", "attachment; filename=#{bfn.to_s.inspect}"
|
72
|
+
a.header.add "Content-Type", "#{t.content_type}; name=#{bfn.to_s.inspect}"
|
73
73
|
a.header.add "Content-Transfer-Encoding", t.encoding
|
74
74
|
a.body =
|
75
75
|
case t.encoding
|
@@ -77,12 +77,20 @@ module RMail
|
|
77
77
|
[IO.read(fn)].pack "m"
|
78
78
|
when "quoted-printable"
|
79
79
|
[IO.read(fn)].pack "M"
|
80
|
+
when "7bit", "8bit"
|
81
|
+
IO.read(fn)
|
80
82
|
else
|
81
83
|
raise EncodingUnsupportedError, t.encoding
|
82
84
|
end
|
83
85
|
|
84
86
|
add_part a
|
85
87
|
end
|
88
|
+
|
89
|
+
def charset
|
90
|
+
if header.field?("content-type") && header.fetch("content-type") =~ /charset="?(.*?)"?(;|$)/
|
91
|
+
$1
|
92
|
+
end
|
93
|
+
end
|
86
94
|
end
|
87
95
|
end
|
88
96
|
|
@@ -123,21 +131,7 @@ class Object
|
|
123
131
|
ret
|
124
132
|
end
|
125
133
|
|
126
|
-
##
|
127
|
-
## like:
|
128
|
-
##
|
129
|
-
## x = expensive_operation
|
130
|
-
## log "got #{x}"
|
131
|
-
## x
|
132
|
-
##
|
133
|
-
## now becomes:
|
134
|
-
##
|
135
|
-
## with(expensive_operation) { |x| log "got #{x}" }
|
136
|
-
##
|
137
|
-
## i'm sure there's pithy comment i could make here about the
|
138
|
-
## superiority of lisp, but fuck lisp.
|
139
|
-
##
|
140
|
-
## addendum: apparently this is a "k combinator". whoda thunk it?
|
134
|
+
## "k combinator"
|
141
135
|
def returning x; yield x; x; end
|
142
136
|
|
143
137
|
## clone of java-style whole-method synchronization
|
@@ -277,14 +271,14 @@ module Enumerable
|
|
277
271
|
|
278
272
|
## returns the maximum shared prefix of an array of strings
|
279
273
|
## optinally excluding a prefix
|
280
|
-
def shared_prefix exclude=""
|
274
|
+
def shared_prefix caseless=false, exclude=""
|
281
275
|
return "" if empty?
|
282
276
|
prefix = ""
|
283
277
|
(0 ... first.length).each do |i|
|
284
|
-
c = first[i]
|
285
|
-
break unless all? { |s| s[i] == c }
|
278
|
+
c = (caseless ? first.downcase : first)[i]
|
279
|
+
break unless all? { |s| (caseless ? s.downcase : s)[i] == c }
|
286
280
|
next if exclude[i] == c
|
287
|
-
prefix +=
|
281
|
+
prefix += first[i].chr
|
288
282
|
end
|
289
283
|
prefix
|
290
284
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: sup
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2007-
|
6
|
+
version: "0.2"
|
7
|
+
date: 2007-10-29 00:00:00 -07:00
|
8
8
|
summary: A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -43,15 +43,18 @@ files:
|
|
43
43
|
- bin/sup-sync
|
44
44
|
- bin/sup-sync-back
|
45
45
|
- doc/FAQ.txt
|
46
|
+
- doc/Hooks.txt
|
47
|
+
- doc/NewUserGuide.txt
|
46
48
|
- doc/Philosophy.txt
|
47
49
|
- doc/TODO
|
48
|
-
- doc/UserGuide.txt
|
49
50
|
- lib/sup.rb
|
50
51
|
- lib/sup/account.rb
|
51
52
|
- lib/sup/buffer.rb
|
52
53
|
- lib/sup/colormap.rb
|
53
54
|
- lib/sup/contact.rb
|
55
|
+
- lib/sup/crypto.rb
|
54
56
|
- lib/sup/draft.rb
|
57
|
+
- lib/sup/hook.rb
|
55
58
|
- lib/sup/imap.rb
|
56
59
|
- lib/sup/index.rb
|
57
60
|
- lib/sup/keymap.rb
|
@@ -62,6 +65,7 @@ files:
|
|
62
65
|
- lib/sup/mbox/loader.rb
|
63
66
|
- lib/sup/mbox/ssh-file.rb
|
64
67
|
- lib/sup/mbox/ssh-loader.rb
|
68
|
+
- lib/sup/message-chunks.rb
|
65
69
|
- lib/sup/message.rb
|
66
70
|
- lib/sup/mode.rb
|
67
71
|
- lib/sup/modes/buffer-list-mode.rb
|