]> git.cworth.org Git - sup/commitdiff
Merge branch 'better-buffer-list'
authorWilliam Morgan <wmorgan-sup@masanjin.net>
Mon, 18 May 2009 14:31:55 +0000 (07:31 -0700)
committerWilliam Morgan <wmorgan-sup@masanjin.net>
Mon, 18 May 2009 14:31:55 +0000 (07:31 -0700)
1  2 
bin/sup
lib/sup/buffer.rb
lib/sup/modes/edit-message-mode.rb
lib/sup/modes/thread-index-mode.rb
lib/sup/poll.rb

diff --combined bin/sup
index 4f72d0cc90ceeead028d66bb99f2be3db3e993e9,77a5da3ab11abd26c3d16193d6f8f6b857234074..0af3d11ecfea671bc299342f6ca410d6cb83bf12
+++ b/bin/sup
@@@ -67,9 -67,9 +67,9 @@@ global_keymap = Keymap.new do |k
    k.add :quit_now, "Quit Sup immediately", 'Q'
    k.add :help, "Show help", '?'
    k.add :roll_buffers, "Switch to next buffer", 'b'
#  k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
+   k.add :roll_buffers_backwards, "Switch to previous buffer", 'B'
    k.add :kill_buffer, "Kill the current buffer", 'x'
-   k.add :list_buffers, "List all buffers", 'B'
+   k.add :list_buffers, "List all buffers", ';'
    k.add :list_contacts, "List contacts", 'C'
    k.add :redraw, "Redraw screen", :ctrl_l
    k.add :search, "Search all messages", '\\', 'F'
    k.add :recall_draft, "Edit most recent draft message", 'R'
  end
  
 +## the following magic enables wide characters when used with a ruby
 +## ncurses.so that's been compiled against libncursesw. (note the w.) why
 +## this works, i have no idea. much like pretty much every aspect of
 +## dealing with curses.  cargo cult programming at its best.
 +##
 +## BSD users: if libc.so.6 is not found, try installing compat6x.
 +require 'dl/import'
 +module LibC
 +  extend DL::Importable
 +  setlocale_lib = case Config::CONFIG['arch']
 +    when /darwin/; "libc.dylib"
 +    when /cygwin/; "cygwin1.dll"
 +    else; "libc.so.6"
 +  end
 +
 +  Redwood::log "dynamically loading setlocale() from #{setlocale_lib}"
 +  begin
 +    dlload setlocale_lib
 +    extern "void setlocale(int, const char *)"
 +    Redwood::log "setting locale..."
 +    LibC.setlocale(6, "")  # LC_ALL == 6
 +  rescue RuntimeError => e
 +    Redwood::log "cannot dlload setlocale(); ncurses wide character support probably broken."
 +    Redwood::log "dlload error was #{e.class}: #{e.message}"
 +    if Config::CONFIG['arch'] =~ /bsd/
 +      Redwood::log "BSD variant detected. You may have to install a compat6x package to acquire libc."
 +    end
 +  end
 +end
 +
  def start_cursing
    Ncurses.initscr
    Ncurses.noecho
@@@ -260,7 -230,7 +260,7 @@@ begi
      when :kill_buffer
        bm.kill_buffer_safely bm.focus_buf
      when :list_buffers
-       bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
+       bm.spawn_unless_exists("buffer list", :system => true) { BufferListMode.new }
      when :list_contacts
        b, new = bm.spawn_unless_exists("Contact List") { ContactListMode.new }
        b.mode.load_in_background if new
      when :search_unread
        SearchResultsMode.spawn_from_query "is:unread"
      when :list_labels
 -      labels = LabelManager.listable_labels.map { |l| LabelManager.string_for l }
 +      labels = LabelManager.all_labels.map { |l| LabelManager.string_for l }
        user_label = bm.ask_with_completions :label, "Show threads with label (enter for listing): ", labels
        unless user_label.nil?
          if user_label.empty?
diff --combined lib/sup/buffer.rb
index 2fbb679a47ac490f107ecc64fcd714ec93a0c840,59915345b14528f6f059efcb22fa82182b31dab2..cb61e12ffd19df6a2ccc0a2df7c54ec80066938e
@@@ -51,8 -51,8 +51,8 @@@ module Redwoo
  class InputSequenceAborted < StandardError; end
  
  class Buffer
-   attr_reader :mode, :x, :y, :width, :height, :title
-   bool_reader :dirty
+   attr_reader :mode, :x, :y, :width, :height, :title, :atime
+   bool_reader :dirty, :system
    bool_accessor :force_to_top
  
    def initialize window, mode, width, height, opts={}
@@@ -63,6 -63,8 +63,8 @@@
      @title = opts[:title] || ""
      @force_to_top = opts[:force_to_top] || false
      @x, @y, @width, @height = 0, 0, width, height
+     @atime = Time.at 0
+     @system = opts[:system] || false
    end
  
    def content_height; @height - 1; end
@@@ -97,6 -99,7 +99,7 @@@
      @mode.draw
      draw_status status
      commit
+     @atime = Time.now
    end
  
    ## s nil means a blank line!
@@@ -338,7 -341,7 +341,7 @@@ EO
      ## w = Ncurses::WINDOW.new(height, width, (opts[:top] || 0),
      ## (opts[:left] || 0))
      w = Ncurses.stdscr
-     b = Buffer.new w, mode, width, height, :title => realtitle, :force_to_top => (opts[:force_to_top] || false)
+     b = Buffer.new w, mode, width, height, :title => realtitle, :force_to_top => opts[:force_to_top], :system => opts[:system]
      mode.buffer = b
      @name_map[realtitle] = b
  
      default = default_labels.join(" ")
      default += " " unless default.empty?
  
 -    applyable_labels = (LabelManager.applyable_labels - forbidden_labels).map { |l| LabelManager.string_for l }.sort_by { |s| s.downcase }
 +    # here I would prefer to give more control and allow all_labels instead of
 +    # user_defined_labels only
 +    applyable_labels = (LabelManager.user_defined_labels - forbidden_labels).map { |l| LabelManager.string_for l }.sort_by { |s| s.downcase }
  
      answer = ask_many_with_completions domain, question, applyable_labels, default
  
      answer = BufferManager.ask_many_emails_with_completions domain, question, completions, default
  
      if answer
 -      answer.split_on_commas.map { |x| ContactManager.contact_for(x) || PersonManager.person_for(x) }
 +      answer.split_on_commas.map { |x| ContactManager.contact_for(x) || Person.from_address(x) }
      end
    end
  
index 31aa8972766c34d17ae8f9cda5379b5363af559f,407b23cb102b4d2dd77845cc77db342f696058e1..353e76ac137644d9a1389705d997630501a2a6ab
@@@ -145,6 -145,8 +145,8 @@@ EO
      !edited? || BufferManager.ask_yes_or_no("Discard message?")
    end
  
+   def unsaved?; edited? end
    def attach_file
      fn = BufferManager.ask_for_filename :attachment, "File name (enter for browser): "
      return unless fn
@@@ -321,8 -323,8 +323,8 @@@ protecte
  
      ## do whatever crypto transformation is necessary
      if @crypto_selector && @crypto_selector.val != :none
 -      from_email = PersonManager.person_for(@header["From"]).email
 -      to_email = [@header["To"], @header["Cc"], @header["Bcc"]].flatten.compact.map { |p| PersonManager.person_for(p).email }
 +      from_email = Person.from_address(@header["From"]).email
 +      to_email = [@header["To"], @header["Cc"], @header["Bcc"]].flatten.compact.map { |p| Person.from_address(p).email }
  
        m = CryptoManager.send @crypto_selector.val, from_email, to_email, m
      end
@@@ -412,7 -414,7 +414,7 @@@ privat
    end
  
    def sig_lines
 -    p = PersonManager.person_for(@header["From"])
 +    p = Person.from_address(@header["From"])
      from_email = p && p.email
  
      ## first run the hook
index cd9a0277689a9debba64003332345adc96d530fb,a45175dda8f34781fbc0723868105268245db561..56dcdff2df5f139c0129c984b0f02696d6d2cd70
@@@ -42,7 -42,7 +42,7 @@@ EO
      k.add :toggle_tagged, "Tag/untag selected thread", 't'
      k.add :toggle_tagged_all, "Tag/untag all threads", 'T'
      k.add :tag_matching, "Tag matching threads", 'g'
-     k.add :apply_to_tagged, "Apply next command to all tagged threads", ';'
+     k.add :apply_to_tagged, "Apply next command to all tagged threads", '+', '='
      k.add :join_threads, "Force tagged threads to be joined into the same thread", '#'
    end
  
@@@ -68,8 -68,6 +68,8 @@@
  
      UpdateManager.register self
  
 +    @save_thread_mutex = Mutex.new
 +
      @last_load_more_size = nil
      to_load_more do |size|
        next if @last_load_more_size == 0
@@@ -79,6 -77,7 +79,7 @@@
      end
    end
  
+   def unsaved?; dirty? end
    def lines; @text.length; end
    def [] i; @text[i]; end
    def contains_thread? t; @threads.include?(t) end
      BufferManager.flash "#{threads.size.pluralize 'Thread'} killed."
    end
  
 -  def save
 -    BufferManager.say("Saving contacts...") { ContactManager.instance.save }
 -    dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } }
 -    return if dirty_threads.empty?
 +  def save background=true
 +    if background
 +      Redwood::reporting_thread("saving thread") { actually_save }
 +    else
 +      actually_save
 +    end
 +  end
 +
 +  def actually_save
 +    @save_thread_mutex.synchronize do
 +      BufferManager.say("Saving contacts...") { ContactManager.instance.save }
 +      dirty_threads = @mutex.synchronize { (@threads + @hidden_threads.keys).select { |t| t.dirty? } }
 +      next if dirty_threads.empty?
  
 -    BufferManager.say("Saving threads...") do |say_id|
 -      dirty_threads.each_with_index do |t, i|
 -        BufferManager.say "Saving modified thread #{i + 1} of #{dirty_threads.length}...", say_id
 -        t.save Index
 +      BufferManager.say("Saving threads...") do |say_id|
 +        dirty_threads.each_with_index do |t, i|
 +          BufferManager.say "Saving modified thread #{i + 1} of #{dirty_threads.length}...", say_id
 +          t.save Index
 +        end
        end
      end
    end
        sleep 0.1 # TODO: necessary?
        BufferManager.erase_flash
      end
 -    save
 +    save false
      super
    end
  
    end
  
    def multi_edit_labels threads
 -    user_labels = BufferManager.ask_for_labels :add_labels, "Add labels: ", [], @hidden_labels
 +    user_labels = BufferManager.ask_for_labels :labels, "Add/remove labels (use -label to remove): ", [], @hidden_labels
      return unless user_labels
 -    
 -    hl = user_labels.select { |l| @hidden_labels.member? l }
 +
 +    user_labels.map! { |l| (l.to_s =~ /^-/)? [l.to_s.gsub(/^-?/, '').to_sym, true] : [l, false] }
 +    hl = user_labels.select { |(l,_)| @hidden_labels.member? l }
      if hl.empty?
 -      threads.each { |t| user_labels.each { |l| t.apply_label l } }
 -      user_labels.each { |l| LabelManager << l }
 +      threads.each do |t|
 +        user_labels.each do |(l, to_remove)|
 +          if to_remove
 +            t.remove_label l
 +          else
 +            t.apply_label l
 +          end
 +        end
 +      end
 +      user_labels.each { |(l,_)| LabelManager << l }
      else
        BufferManager.flash "'#{hl}' is a reserved label!"
      end
@@@ -753,7 -733,6 +754,6 @@@ protecte
        (t.labels - @hidden_labels).map { |label| [:label_color, "+#{label} "] } +
        [[:snippet_color, snippet]
      ]
    end
  
    def dirty?; @mutex.synchronize { (@hidden_threads.keys + @threads).any? { |t| t.dirty? } } end
diff --combined lib/sup/poll.rb
index 5027218c49d66318b309a062c1d222d81699d3a1,92305c9fde1b25a24e5160e24ffbd17c970b623a..d85abb5fe9557f993e8138b9a8068d66305b7bb2
@@@ -40,7 -40,7 +40,7 @@@ EO
    end
  
    def buffer
-     b, new = BufferManager.spawn_unless_exists("<poll for new messages>", :hidden => true) { PollMode.new }
+     b, new = BufferManager.spawn_unless_exists("poll for new messages", :hidden => true, :system => true) { PollMode.new }
      b
    end
  
          numi = 0
          add_messages_from source do |m, offset, entry|
            ## always preserve the labels on disk.
 -          m.labels = entry[:label].split(/\s+/).map { |x| x.intern } if entry
 +          m.labels = ((m.labels - [:unread, :inbox]) + entry[:label].split(/\s+/).map { |x| x.intern }).uniq if entry
            yield "Found message at #{offset} with labels {#{m.labels * ', '}}"
            unless entry
              num += 1
 -            from_and_subj << [m.from.longname, m.subj]
 +            from_and_subj << [m.from && m.from.longname, m.subj]
              if m.has_label?(:inbox) && ([:spam, :deleted, :killed] & m.labels).empty?
 -              from_and_subj_inbox << [m.from.longname, m.subj]
 +              from_and_subj_inbox << [m.from && m.from.longname, m.subj]
                numi += 1 
              end
            end