sup 0.10.2 → 0.11
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.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data/CONTRIBUTORS +11 -9
 - data/History.txt +14 -0
 - data/README.txt +3 -11
 - data/ReleaseNotes +16 -0
 - data/bin/sup +67 -42
 - data/bin/sup-add +2 -20
 - data/bin/sup-config +0 -34
 - data/bin/sup-dump +2 -5
 - data/bin/sup-sync +2 -3
 - data/bin/sup-sync-back +2 -3
 - data/bin/sup-tweak-labels +2 -3
 - data/lib/sup.rb +12 -4
 - data/lib/sup/account.rb +2 -0
 - data/lib/sup/buffer.rb +11 -2
 - data/lib/sup/colormap.rb +59 -49
 - data/lib/sup/connection.rb +63 -0
 - data/lib/sup/crypto.rb +12 -0
 - data/lib/sup/hook.rb +1 -0
 - data/lib/sup/idle.rb +42 -0
 - data/lib/sup/index.rb +562 -47
 - data/lib/sup/keymap.rb +41 -3
 - data/lib/sup/message.rb +1 -1
 - data/lib/sup/mode.rb +8 -0
 - data/lib/sup/modes/console-mode.rb +2 -3
 - data/lib/sup/modes/edit-message-mode.rb +32 -7
 - data/lib/sup/modes/inbox-mode.rb +4 -0
 - data/lib/sup/modes/search-list-mode.rb +188 -0
 - data/lib/sup/modes/search-results-mode.rb +17 -1
 - data/lib/sup/modes/thread-index-mode.rb +43 -10
 - data/lib/sup/modes/thread-view-mode.rb +29 -4
 - data/lib/sup/poll.rb +13 -2
 - data/lib/sup/search.rb +73 -0
 - data/lib/sup/textfield.rb +17 -12
 - data/lib/sup/util.rb +11 -0
 - metadata +45 -46
 - data/bin/sup-convert-ferret-index +0 -84
 - data/lib/ncurses.rb +0 -289
 - data/lib/sup/ferret_index.rb +0 -476
 - data/lib/sup/xapian_index.rb +0 -605
 
    
        data/lib/sup/keymap.rb
    CHANGED
    
    | 
         @@ -1,6 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Redwood
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            class Keymap
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              HookManager.register "keybindings", <<EOS
         
     | 
| 
      
 6 
     | 
    
         
            +
            Add custom keybindings.
         
     | 
| 
      
 7 
     | 
    
         
            +
            Methods:
         
     | 
| 
      
 8 
     | 
    
         
            +
              modes: Hash from mode names to mode classes.
         
     | 
| 
      
 9 
     | 
    
         
            +
              global_keymap: The top-level keymap.
         
     | 
| 
      
 10 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       4 
12 
     | 
    
         
             
              def initialize
         
     | 
| 
       5 
13 
     | 
    
         
             
                @map = {}
         
     | 
| 
       6 
14 
     | 
    
         
             
                @order = []
         
     | 
| 
         @@ -60,10 +68,31 @@ class Keymap 
     | 
|
| 
       60 
68 
     | 
    
         
             
                end
         
     | 
| 
       61 
69 
     | 
    
         
             
              end
         
     | 
| 
       62 
70 
     | 
    
         | 
| 
      
 71 
     | 
    
         
            +
              def delete k
         
     | 
| 
      
 72 
     | 
    
         
            +
                kc = Keymap.keysym_to_keycode(k)
         
     | 
| 
      
 73 
     | 
    
         
            +
                return unless @map.member? kc
         
     | 
| 
      
 74 
     | 
    
         
            +
                entry = @map.delete kc
         
     | 
| 
      
 75 
     | 
    
         
            +
                keys = entry[2]
         
     | 
| 
      
 76 
     | 
    
         
            +
                keys.delete k
         
     | 
| 
      
 77 
     | 
    
         
            +
                @order.delete entry if keys.empty?
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              def add! action, help, *keys
         
     | 
| 
      
 81 
     | 
    
         
            +
                keys.each { |k| delete k }
         
     | 
| 
      
 82 
     | 
    
         
            +
                add action, help, *keys
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       63 
85 
     | 
    
         
             
              def add_multi prompt, key
         
     | 
| 
       64 
     | 
    
         
            -
                 
     | 
| 
       65 
     | 
    
         
            -
                 
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 86 
     | 
    
         
            +
                kc = Keymap.keysym_to_keycode(key)
         
     | 
| 
      
 87 
     | 
    
         
            +
                if @map.member? kc
         
     | 
| 
      
 88 
     | 
    
         
            +
                  action = @map[kc].first
         
     | 
| 
      
 89 
     | 
    
         
            +
                  raise "existing action is not a keymap" unless action.is_a?(Keymap)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  yield action
         
     | 
| 
      
 91 
     | 
    
         
            +
                else
         
     | 
| 
      
 92 
     | 
    
         
            +
                  submap = Keymap.new
         
     | 
| 
      
 93 
     | 
    
         
            +
                  add submap, prompt, key
         
     | 
| 
      
 94 
     | 
    
         
            +
                  yield submap
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
       67 
96 
     | 
    
         
             
              end
         
     | 
| 
       68 
97 
     | 
    
         | 
| 
       69 
98 
     | 
    
         
             
              def action_for kc
         
     | 
| 
         @@ -95,6 +124,15 @@ class Keymap 
     | 
|
| 
       95 
124 
     | 
    
         
             
                llen = lines.max_of { |a, b| a.length }
         
     | 
| 
       96 
125 
     | 
    
         
             
                lines.map { |a, b| sprintf " %#{llen}s : %s", a, b }.join("\n")
         
     | 
| 
       97 
126 
     | 
    
         
             
              end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
              def self.run_hook global_keymap
         
     | 
| 
      
 129 
     | 
    
         
            +
                modes = Hash[Mode.keymaps.map { |klass,keymap| [Mode.make_name(klass.name),klass] }]
         
     | 
| 
      
 130 
     | 
    
         
            +
                locals = {
         
     | 
| 
      
 131 
     | 
    
         
            +
                  :modes => modes,
         
     | 
| 
      
 132 
     | 
    
         
            +
                  :global_keymap => global_keymap,
         
     | 
| 
      
 133 
     | 
    
         
            +
                }
         
     | 
| 
      
 134 
     | 
    
         
            +
                HookManager.run 'keybindings', locals
         
     | 
| 
      
 135 
     | 
    
         
            +
              end
         
     | 
| 
       98 
136 
     | 
    
         
             
            end
         
     | 
| 
       99 
137 
     | 
    
         | 
| 
       100 
138 
     | 
    
         
             
            end
         
     | 
    
        data/lib/sup/message.rb
    CHANGED
    
    | 
         @@ -178,7 +178,7 @@ class Message 
     | 
|
| 
       178 
178 
     | 
    
         | 
| 
       179 
179 
     | 
    
         
             
              ## sanitize message ids by removing spaces and non-ascii characters.
         
     | 
| 
       180 
180 
     | 
    
         
             
              ## also, truncate to 255 characters. all these steps are necessary
         
     | 
| 
       181 
     | 
    
         
            -
              ## to make  
     | 
| 
      
 181 
     | 
    
         
            +
              ## to make the index happy. of course, we probably fuck up a couple
         
     | 
| 
       182 
182 
     | 
    
         
             
              ## valid message ids as well. as long as we're consistent, this
         
     | 
| 
       183 
183 
     | 
    
         
             
              ## should be fine, though.
         
     | 
| 
       184 
184 
     | 
    
         
             
              ##
         
     | 
    
        data/lib/sup/mode.rb
    CHANGED
    
    
| 
         @@ -20,7 +20,6 @@ class Console 
     | 
|
| 
       20 
20 
     | 
    
         
             
              end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
              def xapian; Index.instance.instance_variable_get :@xapian; end
         
     | 
| 
       23 
     | 
    
         
            -
              def ferret; Index.instance.instance_variable_get :@index; end
         
     | 
| 
       24 
23 
     | 
    
         | 
| 
       25 
24 
     | 
    
         
             
              def loglevel; Redwood::Logger.level; end
         
     | 
| 
       26 
25 
     | 
    
         
             
              def set_loglevel(level); Redwood::Logger.level = level; end
         
     | 
| 
         @@ -29,7 +28,7 @@ class Console 
     | 
|
| 
       29 
28 
     | 
    
         | 
| 
       30 
29 
     | 
    
         
             
              ## files that won't cause problems when reloaded
         
     | 
| 
       31 
30 
     | 
    
         
             
              ## TODO expand this list / convert to blacklist
         
     | 
| 
       32 
     | 
    
         
            -
              RELOAD_WHITELIST = %w(sup/ 
     | 
| 
      
 31 
     | 
    
         
            +
              RELOAD_WHITELIST = %w(sup/index.rb sup/modes/console-mode.rb)
         
     | 
| 
       33 
32 
     | 
    
         | 
| 
       34 
33 
     | 
    
         
             
              def reload
         
     | 
| 
       35 
34 
     | 
    
         
             
                old_verbose = $VERBOSE
         
     | 
| 
         @@ -69,7 +68,7 @@ class ConsoleMode < LogMode 
     | 
|
| 
       69 
68 
     | 
    
         
             
              end
         
     | 
| 
       70 
69 
     | 
    
         | 
| 
       71 
70 
     | 
    
         
             
              def initialize
         
     | 
| 
       72 
     | 
    
         
            -
                super
         
     | 
| 
      
 71 
     | 
    
         
            +
                super "console"
         
     | 
| 
       73 
72 
     | 
    
         
             
                @console = Console.new self
         
     | 
| 
       74 
73 
     | 
    
         
             
                @binding = @console.instance_eval { binding }
         
     | 
| 
       75 
74 
     | 
    
         
             
              end
         
     | 
| 
         @@ -3,10 +3,6 @@ require 'socket' # just for gethostname! 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'pathname'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'rmail'
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            # from jcode.rb, not included in ruby 1.9
         
     | 
| 
       7 
     | 
    
         
            -
            PATTERN_UTF8 = '[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]'
         
     | 
| 
       8 
     | 
    
         
            -
            RE_UTF8 = Regexp.new(PATTERN_UTF8, 0, 'n')
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
6 
     | 
    
         
             
            module Redwood
         
     | 
| 
       11 
7 
     | 
    
         | 
| 
       12 
8 
     | 
    
         
             
            class SendmailCommandFailed < StandardError; end
         
     | 
| 
         @@ -40,6 +36,28 @@ Return value: 
     | 
|
| 
       40 
36 
     | 
    
         
             
            	none
         
     | 
| 
       41 
37 
     | 
    
         
             
            EOS
         
     | 
| 
       42 
38 
     | 
    
         | 
| 
      
 39 
     | 
    
         
            +
              HookManager.register "mentions-attachments", <<EOS
         
     | 
| 
      
 40 
     | 
    
         
            +
            Detects if given message mentions attachments the way it is probable
         
     | 
| 
      
 41 
     | 
    
         
            +
            that there should be files attached to the message.
         
     | 
| 
      
 42 
     | 
    
         
            +
            Variables:
         
     | 
| 
      
 43 
     | 
    
         
            +
            	header: a hash of headers. See 'signature' hook for documentation.
         
     | 
| 
      
 44 
     | 
    
         
            +
            	body: an array of lines of body text.
         
     | 
| 
      
 45 
     | 
    
         
            +
            Return value:
         
     | 
| 
      
 46 
     | 
    
         
            +
            	True if attachments are mentioned.
         
     | 
| 
      
 47 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              HookManager.register "crypto-mode", <<EOS
         
     | 
| 
      
 50 
     | 
    
         
            +
            Modifies cryptography settings based on header and message content, before
         
     | 
| 
      
 51 
     | 
    
         
            +
            editing a new message. This can be used to set, for example, default cryptography
         
     | 
| 
      
 52 
     | 
    
         
            +
            settings.
         
     | 
| 
      
 53 
     | 
    
         
            +
            Variables:
         
     | 
| 
      
 54 
     | 
    
         
            +
                header: a hash of headers. See 'signature' hook for documentation.
         
     | 
| 
      
 55 
     | 
    
         
            +
                body: an array of lines of body text.
         
     | 
| 
      
 56 
     | 
    
         
            +
                crypto_selector: the UI element that controls the current cryptography setting.
         
     | 
| 
      
 57 
     | 
    
         
            +
            Return value:
         
     | 
| 
      
 58 
     | 
    
         
            +
                 none
         
     | 
| 
      
 59 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
       43 
61 
     | 
    
         
             
              attr_reader :status
         
     | 
| 
       44 
62 
     | 
    
         
             
              attr_accessor :body, :header
         
     | 
| 
       45 
63 
     | 
    
         
             
              bool_reader :edited
         
     | 
| 
         @@ -92,6 +110,9 @@ EOS 
     | 
|
| 
       92 
110 
     | 
    
         
             
                add_selector @crypto_selector if @crypto_selector
         
     | 
| 
       93 
111 
     | 
    
         | 
| 
       94 
112 
     | 
    
         
             
                HookManager.run "before-edit", :header => @header, :body => @body
         
     | 
| 
      
 113 
     | 
    
         
            +
                if @crypto_selector
         
     | 
| 
      
 114 
     | 
    
         
            +
                  HookManager.run "crypto-mode", :header => @header, :body => @body, :crypto_selector => @crypto_selector
         
     | 
| 
      
 115 
     | 
    
         
            +
                end
         
     | 
| 
       95 
116 
     | 
    
         | 
| 
       96 
117 
     | 
    
         
             
                super opts
         
     | 
| 
       97 
118 
     | 
    
         
             
                regen_text
         
     | 
| 
         @@ -193,7 +214,7 @@ protected 
     | 
|
| 
       193 
214 
     | 
    
         
             
              end
         
     | 
| 
       194 
215 
     | 
    
         | 
| 
       195 
216 
     | 
    
         
             
              def mime_encode_subject string
         
     | 
| 
       196 
     | 
    
         
            -
                return string  
     | 
| 
      
 217 
     | 
    
         
            +
                return string if string.ascii_only?
         
     | 
| 
       197 
218 
     | 
    
         
             
                mime_encode string
         
     | 
| 
       198 
219 
     | 
    
         
             
              end
         
     | 
| 
       199 
220 
     | 
    
         | 
| 
         @@ -202,7 +223,7 @@ protected 
     | 
|
| 
       202 
223 
     | 
    
         
             
              # Encode "bælammet mitt <user@example.com>" into
         
     | 
| 
       203 
224 
     | 
    
         
             
              # "=?utf-8?q?b=C3=A6lammet_mitt?= <user@example.com>
         
     | 
| 
       204 
225 
     | 
    
         
             
              def mime_encode_address string
         
     | 
| 
       205 
     | 
    
         
            -
                return string  
     | 
| 
      
 226 
     | 
    
         
            +
                return string if string.ascii_only?
         
     | 
| 
       206 
227 
     | 
    
         
             
                string.sub(RE_ADDRESS) { |match| mime_encode($1) + $2 }
         
     | 
| 
       207 
228 
     | 
    
         
             
              end
         
     | 
| 
       208 
229 
     | 
    
         | 
| 
         @@ -444,7 +465,11 @@ private 
     | 
|
| 
       444 
465 
     | 
    
         
             
              end
         
     | 
| 
       445 
466 
     | 
    
         | 
| 
       446 
467 
     | 
    
         
             
              def mentions_attachments?
         
     | 
| 
       447 
     | 
    
         
            -
                 
     | 
| 
      
 468 
     | 
    
         
            +
                if HookManager.enabled? "mentions-attachments"
         
     | 
| 
      
 469 
     | 
    
         
            +
                  HookManager.run "mentions-attachments", :header => @header, :body => @body
         
     | 
| 
      
 470 
     | 
    
         
            +
                else
         
     | 
| 
      
 471 
     | 
    
         
            +
                  @body.any? {  |l| l =~ /^[^>]/ && l =~ /\battach(ment|ed|ing|)\b/i }
         
     | 
| 
      
 472 
     | 
    
         
            +
                end
         
     | 
| 
       448 
473 
     | 
    
         
             
              end
         
     | 
| 
       449 
474 
     | 
    
         | 
| 
       450 
475 
     | 
    
         
             
              def top_posting?
         
     | 
    
        data/lib/sup/modes/inbox-mode.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,188 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Redwood
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class SearchListMode < LineCursorMode
         
     | 
| 
      
 4 
     | 
    
         
            +
              register_keymap do |k|
         
     | 
| 
      
 5 
     | 
    
         
            +
                k.add :select_search, "Open search results", :enter
         
     | 
| 
      
 6 
     | 
    
         
            +
                k.add :reload, "Discard saved search list and reload", '@'
         
     | 
| 
      
 7 
     | 
    
         
            +
                k.add :jump_to_next_new, "Jump to next new thread", :tab
         
     | 
| 
      
 8 
     | 
    
         
            +
                k.add :toggle_show_unread_only, "Toggle between showing all saved searches and those with unread mail", 'u'
         
     | 
| 
      
 9 
     | 
    
         
            +
                k.add :delete_selected_search, "Delete selected search", "X"
         
     | 
| 
      
 10 
     | 
    
         
            +
                k.add :rename_selected_search, "Rename selected search", "r"
         
     | 
| 
      
 11 
     | 
    
         
            +
                k.add :edit_selected_search, "Edit selected search", "e"
         
     | 
| 
      
 12 
     | 
    
         
            +
                k.add :add_new_search, "Add new search", "a"
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              HookManager.register "search-list-filter", <<EOS
         
     | 
| 
      
 16 
     | 
    
         
            +
            Filter the search list, typically to sort.
         
     | 
| 
      
 17 
     | 
    
         
            +
            Variables:
         
     | 
| 
      
 18 
     | 
    
         
            +
              counted: an array of counted searches.
         
     | 
| 
      
 19 
     | 
    
         
            +
            Return value:
         
     | 
| 
      
 20 
     | 
    
         
            +
              An array of counted searches with sort_by output structure.
         
     | 
| 
      
 21 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              HookManager.register "search-list-format", <<EOS
         
     | 
| 
      
 24 
     | 
    
         
            +
            Create the sprintf format string for search-list-mode.
         
     | 
| 
      
 25 
     | 
    
         
            +
            Variables:
         
     | 
| 
      
 26 
     | 
    
         
            +
              n_width: the maximum search name width
         
     | 
| 
      
 27 
     | 
    
         
            +
              tmax: the maximum total message count
         
     | 
| 
      
 28 
     | 
    
         
            +
              umax: the maximum unread message count
         
     | 
| 
      
 29 
     | 
    
         
            +
              s_width: the maximum search string width
         
     | 
| 
      
 30 
     | 
    
         
            +
            Return value:
         
     | 
| 
      
 31 
     | 
    
         
            +
              A format string for sprintf
         
     | 
| 
      
 32 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 35 
     | 
    
         
            +
                @searches = []
         
     | 
| 
      
 36 
     | 
    
         
            +
                @text = []
         
     | 
| 
      
 37 
     | 
    
         
            +
                @unread_only = false
         
     | 
| 
      
 38 
     | 
    
         
            +
                super
         
     | 
| 
      
 39 
     | 
    
         
            +
                UpdateManager.register self
         
     | 
| 
      
 40 
     | 
    
         
            +
                regen_text
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              def cleanup
         
     | 
| 
      
 44 
     | 
    
         
            +
                UpdateManager.unregister self
         
     | 
| 
      
 45 
     | 
    
         
            +
                super
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              def lines; @text.length end
         
     | 
| 
      
 49 
     | 
    
         
            +
              def [] i; @text[i] end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def jump_to_next_new
         
     | 
| 
      
 52 
     | 
    
         
            +
                n = ((curpos + 1) ... lines).find { |i| @searches[i][1] > 0 } || (0 ... curpos).find { |i| @searches[i][1] > 0 }
         
     | 
| 
      
 53 
     | 
    
         
            +
                if n
         
     | 
| 
      
 54 
     | 
    
         
            +
                  ## jump there if necessary
         
     | 
| 
      
 55 
     | 
    
         
            +
                  jump_to_line n unless n >= topline && n < botline
         
     | 
| 
      
 56 
     | 
    
         
            +
                  set_cursor_pos n
         
     | 
| 
      
 57 
     | 
    
         
            +
                else
         
     | 
| 
      
 58 
     | 
    
         
            +
                  BufferManager.flash "No saved searches with unread messages."
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              def focus
         
     | 
| 
      
 63 
     | 
    
         
            +
                reload # make sure unread message counts are up-to-date
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              def handle_added_update sender, m
         
     | 
| 
      
 67 
     | 
    
         
            +
                reload
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            protected
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              def toggle_show_unread_only
         
     | 
| 
      
 73 
     | 
    
         
            +
                @unread_only = !@unread_only
         
     | 
| 
      
 74 
     | 
    
         
            +
                reload
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              def reload
         
     | 
| 
      
 78 
     | 
    
         
            +
                regen_text
         
     | 
| 
      
 79 
     | 
    
         
            +
                buffer.mark_dirty if buffer
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              def regen_text
         
     | 
| 
      
 83 
     | 
    
         
            +
                @text = []
         
     | 
| 
      
 84 
     | 
    
         
            +
                searches = SearchManager.all_searches
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                counted = searches.map do |name|
         
     | 
| 
      
 87 
     | 
    
         
            +
                  search_string = SearchManager.search_string_for name
         
     | 
| 
      
 88 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 89 
     | 
    
         
            +
                    query = Index.parse_query search_string
         
     | 
| 
      
 90 
     | 
    
         
            +
                    total = Index.num_results_for :qobj => query[:qobj]
         
     | 
| 
      
 91 
     | 
    
         
            +
                    unread = Index.num_results_for :qobj => query[:qobj], :label => :unread
         
     | 
| 
      
 92 
     | 
    
         
            +
                  rescue Index::ParseError => e
         
     | 
| 
      
 93 
     | 
    
         
            +
                    BufferManager.flash "Problem: #{e.message}!"
         
     | 
| 
      
 94 
     | 
    
         
            +
                    total = 0
         
     | 
| 
      
 95 
     | 
    
         
            +
                    unread = 0
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  [name, search_string, total, unread]
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                if HookManager.enabled? "search-list-filter"
         
     | 
| 
      
 101 
     | 
    
         
            +
                  counts = HookManager.run "search-list-filter", :counted => counted
         
     | 
| 
      
 102 
     | 
    
         
            +
                else
         
     | 
| 
      
 103 
     | 
    
         
            +
                  counts = counted.sort_by { |n, s, t, u| n.downcase }
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                n_width = counts.max_of { |n, s, t, u| n.length }
         
     | 
| 
      
 107 
     | 
    
         
            +
                tmax    = counts.max_of { |n, s, t, u| t }
         
     | 
| 
      
 108 
     | 
    
         
            +
                umax    = counts.max_of { |n, s, t, u| u }
         
     | 
| 
      
 109 
     | 
    
         
            +
                s_width = counts.max_of { |n, s, t, u| s.length }
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                if @unread_only
         
     | 
| 
      
 112 
     | 
    
         
            +
                  counts.delete_if { | n, s, t, u | u == 0 }
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                @searches = []
         
     | 
| 
      
 116 
     | 
    
         
            +
                counts.each do |name, search_string, total, unread|
         
     | 
| 
      
 117 
     | 
    
         
            +
                  fmt = HookManager.run "search-list-format", :n_width => n_width, :tmax => tmax, :umax => umax, :s_width => s_width
         
     | 
| 
      
 118 
     | 
    
         
            +
                  if !fmt
         
     | 
| 
      
 119 
     | 
    
         
            +
                    fmt = "%#{n_width + 1}s %5d %s, %5d unread: %s"
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  @text << [[(unread == 0 ? :labellist_old_color : :labellist_new_color),
         
     | 
| 
      
 122 
     | 
    
         
            +
                      sprintf(fmt, name, total, total == 1 ? " message" : "messages", unread, search_string)]]
         
     | 
| 
      
 123 
     | 
    
         
            +
                  @searches << [name, unread]
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                BufferManager.flash "No saved searches with unread messages!" if counts.empty? && @unread_only
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
              def select_search
         
     | 
| 
      
 130 
     | 
    
         
            +
                name, num_unread = @searches[curpos]
         
     | 
| 
      
 131 
     | 
    
         
            +
                return unless name
         
     | 
| 
      
 132 
     | 
    
         
            +
                SearchResultsMode.spawn_from_query SearchManager.search_string_for(name)
         
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
              def delete_selected_search
         
     | 
| 
      
 136 
     | 
    
         
            +
                name, num_unread = @searches[curpos]
         
     | 
| 
      
 137 
     | 
    
         
            +
                return unless name
         
     | 
| 
      
 138 
     | 
    
         
            +
                reload if SearchManager.delete name
         
     | 
| 
      
 139 
     | 
    
         
            +
              end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
              def rename_selected_search
         
     | 
| 
      
 142 
     | 
    
         
            +
                old_name, num_unread = @searches[curpos]
         
     | 
| 
      
 143 
     | 
    
         
            +
                return unless old_name
         
     | 
| 
      
 144 
     | 
    
         
            +
                new_name = BufferManager.ask :save_search, "Rename this saved search: ", old_name
         
     | 
| 
      
 145 
     | 
    
         
            +
                return unless new_name && new_name !~ /^\s*$/ && new_name != old_name
         
     | 
| 
      
 146 
     | 
    
         
            +
                new_name.strip!
         
     | 
| 
      
 147 
     | 
    
         
            +
                unless SearchManager.valid_name? new_name
         
     | 
| 
      
 148 
     | 
    
         
            +
                  BufferManager.flash "Not renamed: " + SearchManager.name_format_hint
         
     | 
| 
      
 149 
     | 
    
         
            +
                  return
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
                if SearchManager.all_searches.include? new_name
         
     | 
| 
      
 152 
     | 
    
         
            +
                  BufferManager.flash "Not renamed: \"#{new_name}\" already exists"
         
     | 
| 
      
 153 
     | 
    
         
            +
                  return
         
     | 
| 
      
 154 
     | 
    
         
            +
                end
         
     | 
| 
      
 155 
     | 
    
         
            +
                reload if SearchManager.rename old_name, new_name
         
     | 
| 
      
 156 
     | 
    
         
            +
                set_cursor_pos @searches.index([new_name, num_unread])||curpos
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
              def edit_selected_search
         
     | 
| 
      
 160 
     | 
    
         
            +
                name, num_unread = @searches[curpos]
         
     | 
| 
      
 161 
     | 
    
         
            +
                return unless name
         
     | 
| 
      
 162 
     | 
    
         
            +
                old_search_string = SearchManager.search_string_for name
         
     | 
| 
      
 163 
     | 
    
         
            +
                new_search_string = BufferManager.ask :search, "Edit this saved search: ", (old_search_string + " ")
         
     | 
| 
      
 164 
     | 
    
         
            +
                return unless new_search_string && new_search_string !~ /^\s*$/ && new_search_string != old_search_string
         
     | 
| 
      
 165 
     | 
    
         
            +
                reload if SearchManager.edit name, new_search_string.strip
         
     | 
| 
      
 166 
     | 
    
         
            +
                set_cursor_pos @searches.index([name, num_unread])||curpos
         
     | 
| 
      
 167 
     | 
    
         
            +
              end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
              def add_new_search
         
     | 
| 
      
 170 
     | 
    
         
            +
                search_string = BufferManager.ask :search, "New search: "
         
     | 
| 
      
 171 
     | 
    
         
            +
                return unless search_string && search_string !~ /^\s*$/
         
     | 
| 
      
 172 
     | 
    
         
            +
                name = BufferManager.ask :save_search, "Name this search: "
         
     | 
| 
      
 173 
     | 
    
         
            +
                return unless name && name !~ /^\s*$/
         
     | 
| 
      
 174 
     | 
    
         
            +
                name.strip!
         
     | 
| 
      
 175 
     | 
    
         
            +
                unless SearchManager.valid_name? name
         
     | 
| 
      
 176 
     | 
    
         
            +
                  BufferManager.flash "Not saved: " + SearchManager.name_format_hint
         
     | 
| 
      
 177 
     | 
    
         
            +
                  return
         
     | 
| 
      
 178 
     | 
    
         
            +
                end
         
     | 
| 
      
 179 
     | 
    
         
            +
                if SearchManager.all_searches.include? name
         
     | 
| 
      
 180 
     | 
    
         
            +
                  BufferManager.flash "Not saved: \"#{name}\" already exists"
         
     | 
| 
      
 181 
     | 
    
         
            +
                  return
         
     | 
| 
      
 182 
     | 
    
         
            +
                end
         
     | 
| 
      
 183 
     | 
    
         
            +
                reload if SearchManager.add name, search_string.strip
         
     | 
| 
      
 184 
     | 
    
         
            +
                set_cursor_pos @searches.index(@searches.assoc(name))||curpos
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
            end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,6 +8,7 @@ class SearchResultsMode < ThreadIndexMode 
     | 
|
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
              register_keymap do |k|
         
     | 
| 
       10 
10 
     | 
    
         
             
                k.add :refine_search, "Refine search", '|'
         
     | 
| 
      
 11 
     | 
    
         
            +
                k.add :save_search, "Save search", '%'
         
     | 
| 
       11 
12 
     | 
    
         
             
              end
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
              def refine_search
         
     | 
| 
         @@ -16,7 +17,22 @@ class SearchResultsMode < ThreadIndexMode 
     | 
|
| 
       16 
17 
     | 
    
         
             
                SearchResultsMode.spawn_from_query text
         
     | 
| 
       17 
18 
     | 
    
         
             
              end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
               
     | 
| 
      
 20 
     | 
    
         
            +
              def save_search
         
     | 
| 
      
 21 
     | 
    
         
            +
                name = BufferManager.ask :save_search, "Name this search: "
         
     | 
| 
      
 22 
     | 
    
         
            +
                return unless name && name !~ /^\s*$/
         
     | 
| 
      
 23 
     | 
    
         
            +
                name.strip!
         
     | 
| 
      
 24 
     | 
    
         
            +
                unless SearchManager.valid_name? name
         
     | 
| 
      
 25 
     | 
    
         
            +
                  BufferManager.flash "Not saved: " + SearchManager.name_format_hint
         
     | 
| 
      
 26 
     | 
    
         
            +
                  return
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
                if SearchManager.all_searches.include? name
         
     | 
| 
      
 29 
     | 
    
         
            +
                  BufferManager.flash "Not saved: \"#{name}\" already exists"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                BufferManager.flash "Search saved as \"#{name}\"" if SearchManager.add name, @query[:text].strip
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              ## a proper is_relevant? method requires some way of asking the index
         
     | 
| 
       20 
36 
     | 
    
         
             
              ## if an in-memory object satisfies a query. i'm not sure how to do
         
     | 
| 
       21 
37 
     | 
    
         
             
              ## that yet. in the worst case i can make an in-memory index, add
         
     | 
| 
       22 
38 
     | 
    
         
             
              ## the message, and search against it to see if i have > 0 results,
         
     | 
| 
         @@ -12,6 +12,12 @@ class ThreadIndexMode < LineCursorMode 
     | 
|
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
              HookManager.register "index-mode-size-widget", <<EOS
         
     | 
| 
       14 
14 
     | 
    
         
             
            Generates the per-thread size widget for each thread.
         
     | 
| 
      
 15 
     | 
    
         
            +
            Variables:
         
     | 
| 
      
 16 
     | 
    
         
            +
              thread: The message thread to be formatted.
         
     | 
| 
      
 17 
     | 
    
         
            +
            EOS
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              HookManager.register "index-mode-date-widget", <<EOS
         
     | 
| 
      
 20 
     | 
    
         
            +
            Generates the per-thread date widget for each thread.
         
     | 
| 
       15 
21 
     | 
    
         
             
            Variables:
         
     | 
| 
       16 
22 
     | 
    
         
             
              thread: The message thread to be formatted.
         
     | 
| 
       17 
23 
     | 
    
         
             
            EOS
         
     | 
| 
         @@ -53,10 +59,12 @@ EOS 
     | 
|
| 
       53 
59 
     | 
    
         
             
              def initialize hidden_labels=[], load_thread_opts={}
         
     | 
| 
       54 
60 
     | 
    
         
             
                super()
         
     | 
| 
       55 
61 
     | 
    
         
             
                @mutex = Mutex.new # covers the following variables:
         
     | 
| 
       56 
     | 
    
         
            -
                @threads =  
     | 
| 
      
 62 
     | 
    
         
            +
                @threads = []
         
     | 
| 
       57 
63 
     | 
    
         
             
                @hidden_threads = {}
         
     | 
| 
       58 
64 
     | 
    
         
             
                @size_widget_width = nil
         
     | 
| 
       59 
     | 
    
         
            -
                @size_widgets =  
     | 
| 
      
 65 
     | 
    
         
            +
                @size_widgets = []
         
     | 
| 
      
 66 
     | 
    
         
            +
                @date_widget_width = nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                @date_widgets = []
         
     | 
| 
       60 
68 
     | 
    
         
             
                @tags = Tagger.new self
         
     | 
| 
       61 
69 
     | 
    
         | 
| 
       62 
70 
     | 
    
         
             
                ## these guys, and @text and @lines, are not covered
         
     | 
| 
         @@ -111,7 +119,7 @@ EOS 
     | 
|
| 
       111 
119 
     | 
    
         
             
                  mode = ThreadViewMode.new t, @hidden_labels, self
         
     | 
| 
       112 
120 
     | 
    
         
             
                  BufferManager.spawn t.subj, mode
         
     | 
| 
       113 
121 
     | 
    
         
             
                  BufferManager.draw_screen
         
     | 
| 
       114 
     | 
    
         
            -
                  mode.jump_to_first_open
         
     | 
| 
      
 122 
     | 
    
         
            +
                  mode.jump_to_first_open if $config[:jump_to_open_message]
         
     | 
| 
       115 
123 
     | 
    
         
             
                  BufferManager.draw_screen # lame TODO: make this unnecessary
         
     | 
| 
       116 
124 
     | 
    
         
             
                  ## the first draw_screen is needed before topline and botline
         
     | 
| 
       117 
125 
     | 
    
         
             
                  ## are set, and the second to show the cursor having moved
         
     | 
| 
         @@ -226,6 +234,8 @@ EOS 
     | 
|
| 
       226 
234 
     | 
    
         
             
                  @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| [t.date, t.first.id] }.reverse
         
     | 
| 
       227 
235 
     | 
    
         
             
                  @size_widgets = @threads.map { |t| size_widget_for_thread t }
         
     | 
| 
       228 
236 
     | 
    
         
             
                  @size_widget_width = @size_widgets.max_of { |w| w.display_length }
         
     | 
| 
      
 237 
     | 
    
         
            +
                  @date_widgets = @threads.map { |t| date_widget_for_thread t }
         
     | 
| 
      
 238 
     | 
    
         
            +
                  @date_widget_width = @date_widgets.max_of { |w| w.display_length }
         
     | 
| 
       229 
239 
     | 
    
         
             
                end
         
     | 
| 
       230 
240 
     | 
    
         
             
                set_cursor_pos @threads.index(old_cursor_thread)||curpos
         
     | 
| 
       231 
241 
     | 
    
         | 
| 
         @@ -651,7 +661,7 @@ EOS 
     | 
|
| 
       651 
661 
     | 
    
         
             
                if (l = lines) == 0
         
     | 
| 
       652 
662 
     | 
    
         
             
                  "line 0 of 0"
         
     | 
| 
       653 
663 
     | 
    
         
             
                else
         
     | 
| 
       654 
     | 
    
         
            -
                  "line #{curpos + 1} of #{l} 
     | 
| 
      
 664 
     | 
    
         
            +
                  "line #{curpos + 1} of #{l}"
         
     | 
| 
       655 
665 
     | 
    
         
             
                end
         
     | 
| 
       656 
666 
     | 
    
         
             
              end
         
     | 
| 
       657 
667 
     | 
    
         | 
| 
         @@ -719,6 +729,10 @@ protected 
     | 
|
| 
       719 
729 
     | 
    
         
             
                HookManager.run("index-mode-size-widget", :thread => t) || default_size_widget_for(t)
         
     | 
| 
       720 
730 
     | 
    
         
             
              end
         
     | 
| 
       721 
731 
     | 
    
         | 
| 
      
 732 
     | 
    
         
            +
              def date_widget_for_thread t
         
     | 
| 
      
 733 
     | 
    
         
            +
                HookManager.run("index-mode-date-widget", :thread => t) || default_date_widget_for(t)
         
     | 
| 
      
 734 
     | 
    
         
            +
              end
         
     | 
| 
      
 735 
     | 
    
         
            +
             
     | 
| 
       722 
736 
     | 
    
         
             
              def cursor_thread; @mutex.synchronize { @threads[curpos] }; end
         
     | 
| 
       723 
737 
     | 
    
         | 
| 
       724 
738 
     | 
    
         
             
              def drop_all_threads
         
     | 
| 
         @@ -734,6 +748,7 @@ protected 
     | 
|
| 
       734 
748 
     | 
    
         
             
                  @hidden_threads[t] = true
         
     | 
| 
       735 
749 
     | 
    
         
             
                  @threads.delete_at i
         
     | 
| 
       736 
750 
     | 
    
         
             
                  @size_widgets.delete_at i
         
     | 
| 
      
 751 
     | 
    
         
            +
                  @date_widgets.delete_at i
         
     | 
| 
       737 
752 
     | 
    
         
             
                  @tags.drop_tag_for t
         
     | 
| 
       738 
753 
     | 
    
         
             
                end
         
     | 
| 
       739 
754 
     | 
    
         
             
              end
         
     | 
| 
         @@ -745,9 +760,12 @@ protected 
     | 
|
| 
       745 
760 
     | 
    
         | 
| 
       746 
761 
     | 
    
         
             
                @mutex.synchronize do
         
     | 
| 
       747 
762 
     | 
    
         
             
                  @size_widgets[l] = size_widget_for_thread @threads[l]
         
     | 
| 
      
 763 
     | 
    
         
            +
                  @date_widgets[l] = date_widget_for_thread @threads[l]
         
     | 
| 
       748 
764 
     | 
    
         | 
| 
       749 
     | 
    
         
            -
                  ## if  
     | 
| 
       750 
     | 
    
         
            -
                  need_update = 
     | 
| 
      
 765 
     | 
    
         
            +
                  ## if a widget size has increased, we need to redraw everyone
         
     | 
| 
      
 766 
     | 
    
         
            +
                  need_update =
         
     | 
| 
      
 767 
     | 
    
         
            +
                    (@size_widgets[l].size > @size_widget_width) or
         
     | 
| 
      
 768 
     | 
    
         
            +
                    (@date_widgets[l].size > @date_widget_width)
         
     | 
| 
       751 
769 
     | 
    
         
             
                end
         
     | 
| 
       752 
770 
     | 
    
         | 
| 
       753 
771 
     | 
    
         
             
                if need_update
         
     | 
| 
         @@ -793,14 +811,24 @@ protected 
     | 
|
| 
       793 
811 
     | 
    
         
             
                  result << [name, new[a]]
         
     | 
| 
       794 
812 
     | 
    
         
             
                end
         
     | 
| 
       795 
813 
     | 
    
         | 
| 
      
 814 
     | 
    
         
            +
                if result.size == 1 && (author_and_newness = result.assoc("me"))
         
     | 
| 
      
 815 
     | 
    
         
            +
                  unless (recipients = t.participants - t.authors).empty?
         
     | 
| 
      
 816 
     | 
    
         
            +
                    result = recipients.collect do |r|
         
     | 
| 
      
 817 
     | 
    
         
            +
                      break if limit && result.size >= limit
         
     | 
| 
      
 818 
     | 
    
         
            +
                      name = (recipients.size == 1) ? r.mediumname : r.shortname
         
     | 
| 
      
 819 
     | 
    
         
            +
                      ["(#{name})", author_and_newness[1]]
         
     | 
| 
      
 820 
     | 
    
         
            +
                    end
         
     | 
| 
      
 821 
     | 
    
         
            +
                  end
         
     | 
| 
      
 822 
     | 
    
         
            +
                end
         
     | 
| 
      
 823 
     | 
    
         
            +
             
     | 
| 
       796 
824 
     | 
    
         
             
                result
         
     | 
| 
       797 
825 
     | 
    
         
             
              end
         
     | 
| 
       798 
826 
     | 
    
         | 
| 
       799 
827 
     | 
    
         
             
              AUTHOR_LIMIT = 5
         
     | 
| 
       800 
828 
     | 
    
         
             
              def text_for_thread_at line
         
     | 
| 
       801 
     | 
    
         
            -
                t, size_widget = @mutex.synchronize  
     | 
| 
       802 
     | 
    
         
            -
             
     | 
| 
       803 
     | 
    
         
            -
                 
     | 
| 
      
 829 
     | 
    
         
            +
                t, size_widget, date_widget = @mutex.synchronize do
         
     | 
| 
      
 830 
     | 
    
         
            +
                  [@threads[line], @size_widgets[line], @date_widgets[line]]
         
     | 
| 
      
 831 
     | 
    
         
            +
                end
         
     | 
| 
       804 
832 
     | 
    
         | 
| 
       805 
833 
     | 
    
         
             
                starred = t.has_label? :starred
         
     | 
| 
       806 
834 
     | 
    
         | 
| 
         @@ -851,10 +879,11 @@ protected 
     | 
|
| 
       851 
879 
     | 
    
         
             
                snippet = t.snippet + (t.snippet.empty? ? "" : "...")
         
     | 
| 
       852 
880 
     | 
    
         | 
| 
       853 
881 
     | 
    
         
             
                size_widget_text = sprintf "%#{ @size_widget_width}s", size_widget
         
     | 
| 
      
 882 
     | 
    
         
            +
                date_widget_text = sprintf "%#{ @date_widget_width}s", date_widget
         
     | 
| 
       854 
883 
     | 
    
         | 
| 
       855 
884 
     | 
    
         
             
                [ 
         
     | 
| 
       856 
885 
     | 
    
         
             
                  [:tagged_color, @tags.tagged?(t) ? ">" : " "],
         
     | 
| 
       857 
     | 
    
         
            -
                  [:date_color,  
     | 
| 
      
 886 
     | 
    
         
            +
                  [:date_color, date_widget_text],
         
     | 
| 
       858 
887 
     | 
    
         
             
                  (starred ? [:starred_color, "*"] : [:none, " "]),
         
     | 
| 
       859 
888 
     | 
    
         
             
                ] +
         
     | 
| 
       860 
889 
     | 
    
         
             
                  from +
         
     | 
| 
         @@ -883,6 +912,10 @@ private 
     | 
|
| 
       883 
912 
     | 
    
         
             
                end
         
     | 
| 
       884 
913 
     | 
    
         
             
              end
         
     | 
| 
       885 
914 
     | 
    
         | 
| 
      
 915 
     | 
    
         
            +
              def default_date_widget_for t
         
     | 
| 
      
 916 
     | 
    
         
            +
                t.date.to_nice_s
         
     | 
| 
      
 917 
     | 
    
         
            +
              end
         
     | 
| 
      
 918 
     | 
    
         
            +
             
     | 
| 
       886 
919 
     | 
    
         
             
              def from_width
         
     | 
| 
       887 
920 
     | 
    
         
             
                [(buffer.content_width.to_f * 0.2).to_i, MIN_FROM_WIDTH].max
         
     | 
| 
       888 
921 
     | 
    
         
             
              end
         
     |