X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=bin%2Fsup;h=7314227859aadb65cbfbe1297aec45e29754fd85;hb=b52ec99788262909aceeefeb89a5cdd43d6b66d6;hp=708e76eb7a1dabfe32202b67a0bd9112d7c275b6;hpb=9031760dc98fc879291bb9ae9502fc66ff41270d;p=sup diff --git a/bin/sup b/bin/sup index 708e76e..7314227 100644 --- a/bin/sup +++ b/bin/sup @@ -2,38 +2,66 @@ require 'rubygems' require 'ncurses' +require 'curses' +require 'fileutils' +require 'trollop' require "sup" -Thread.abort_on_exception = true # make debugging possible +BIN_VERSION = "git" -module Redwood +unless Redwood::VERSION == BIN_VERSION + $stderr.puts < e - $exception ||= e - raise - end - end +Error: version mismatch! +The sup executable is at version #{BIN_VERSION.inspect}. +The sup libraries are at version #{Redwood::VERSION.inspect}. + +Is your development environment conflicting with rubygems? +EOS + exit(-1) +end + +$exceptions = [] +$opts = Trollop::options do + version "sup v#{Redwood::VERSION}" + banner < String +end + +if $opts[:list_hooks] + Redwood::HookManager.print_hooks + exit end -module_function :reporting_thread + +Thread.abort_on_exception = true # make debugging possible + +module Redwood global_keymap = Keymap.new do |k| k.add :quit, "Quit Redwood", 'q' k.add :help, "Show help", 'H', '?' 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", 'A' + k.add :list_buffers, "List all buffers", 'B' k.add :list_contacts, "List contacts", 'C' k.add :redraw, "Redraw screen", :ctrl_l - k.add :search, "Search messages", '/' + k.add :search, "Search all messages", '\\', 'F' k.add :list_labels, "List labels", 'L' k.add :poll, "Poll for new messages", 'P' - k.add :compose, "Compose new message", 'm' + k.add :compose, "Compose new message", 'm', 'c' + k.add :nothing, "Do nothing", :ctrl_g + k.add :recall_draft, "Edit most recent draft message", 'R' end def start_cursing @@ -43,55 +71,85 @@ def start_cursing Ncurses.stdscr.keypad 1 Ncurses.curs_set 0 Ncurses.start_color + $cursing = true end def stop_cursing + return unless $cursing Ncurses.curs_set 1 Ncurses.echo Ncurses.endwin end module_function :start_cursing, :stop_cursing -Redwood::SentManager.new Redwood::SENT_FN -Redwood::ContactManager.new Redwood::CONTACT_FN -Redwood::LabelManager.new Redwood::LABEL_FN -Redwood::AccountManager.new $config[:accounts] -Redwood::DraftManager.new Redwood::DRAFT_DIR -Redwood::UpdateManager.new -Redwood::PollManager.new - -Index.new.load -log "loaded #{Index.size} messages from index" - -if(s = Index.source_for DraftManager.source_name) - DraftManager.source = s -else - Index.add_source DraftManager.new_source -end +Index.new +begin + Index.lock +rescue Index::LockError => e + require 'highline' + + h = HighLine.new + h.wrap_at = :auto + h.say Index.fancy_lock_error_message_for(e) -if(s = Index.source_for SentManager.source_name) - SentManager.source = s -else - Index.add_source SentManager.new_source + case h.ask("Should I ask that process to kill itself? ") + when /^\s*y\s*$/i + h.say "Ok, suggesting sepuku..." + FileUtils.touch Redwood::SUICIDE_FN + sleep SuicideManager::DELAY * 2 + FileUtils.rm_f Redwood::SUICIDE_FN + h.say "Let's try that again." + retry + else + h.say < :search_highlight_color end - log "initializing buffer manager" bm = BufferManager.new log "initializing mail index buffer" imode = InboxMode.new - ibuf = bm.spawn "inbox", imode + ibuf = bm.spawn "Inbox", imode - log "ready for (inter)action!" + log "ready for interaction!" Logger.make_buf bm.draw_screen - imode.load_more_threads ibuf.content_height - reporting_thread { sleep 3; PollManager.poll } + Index.usual_sources.each do |s| + next unless s.respond_to? :connect + reporting_thread("call #connect on #{s}") do + begin + s.connect + rescue SourceError => e + Redwood::log "fatal error loading from #{s}: #{e.message}" + end + end + end unless $opts[:no_initial_poll] + + imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread("poll after loading inbox") { sleep 1; PollManager.poll } unless $opts[:no_threads] || $opts[:no_initial_poll] } + + unless $opts[:no_threads] + PollManager.start + SuicideManager.start + Index.start_lock_update_thread + end - until $exception - bm.draw_screen + if $opts[:search] + SearchResultsMode.spawn_from_query $opts[:search] + end + + until $exceptions.nonempty? || SuicideManager.die? c = Ncurses.nonblocking_getch + next unless c bm.erase_flash - if c == Ncurses::KEY_RESIZE - bm.handle_resize - elsif c - unless bm.handle_input(c) - x = global_keymap.action_for c - case x - when :quit - break - when :help - curmode = bm.focus_buf.mode - bm.spawn_unless_exists("") { HelpMode.new curmode, global_keymap } - when :roll_buffers - bm.roll_buffers - when :roll_buffers_backwards - bm.roll_buffers_backwards - when :kill_buffer - bm.kill_buffer bm.focus_buf if bm.focus_buf.mode.killable? - when :list_buffers - bm.spawn_unless_exists("Buffer List") { BufferListMode.new } - when :list_contacts - bm.spawn_unless_exists("Contact List") { ContactListMode.new } - when :search - text = bm.ask :search, "query: " - next unless text && text !~ /^\s*$/ - - begin - qobj = Index.parse_user_query_string text - short_text = text.length < 20 ? text : text[0 ... 20] + "..." - log "built query from #{text.inspect}: #{qobj}" - mode = SearchResultsMode.new qobj - bm.spawn "search: \"#{short_text}\"", mode - mode.load_more_threads mode.buffer.content_height - rescue Ferret::QueryParser::QueryParseException => e - bm.flash "Couldn't parse query." - end - - when :list_labels - b = bm.spawn_unless_exists("Label List") { LabelListMode.new } - b.mode.load_in_background - when :compose - mode = ComposeMode.new - bm.spawn "New Message", mode - mode.edit - when :poll - bm.raise_to_front PollManager.buffer - PollManager.poll - when :nothing - when :redraw - bm.completely_redraw_screen + action = + begin + if bm.handle_input c + :nothing + else + bm.resolve_input_with_keymap c, global_keymap + end + rescue InputSequenceAborted + :nothing + end + + case action + when :quit + break if bm.kill_all_buffers_safely + when :help + curmode = bm.focus_buf.mode + bm.spawn_unless_exists("") { HelpMode.new curmode, global_keymap } + when :roll_buffers + bm.roll_buffers + when :roll_buffers_backwards + bm.roll_buffers_backwards + when :kill_buffer + bm.kill_buffer_safely bm.focus_buf + when :list_buffers + bm.spawn_unless_exists("Buffer List") { BufferListMode.new } + when :list_contacts + b, new = bm.spawn_unless_exists("Contact List") { ContactListMode.new } + b.mode.load_in_background if new + when :search + query = BufferManager.ask :search, "search all messages: " + next unless query && query !~ /^\s*$/ + SearchResultsMode.spawn_from_query query + when :list_labels + labels = LabelManager.listable_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? + bm.spawn_unless_exists("Label list") { LabelListMode.new } if user_label && user_label.empty? else - bm.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}." + LabelSearchResultsMode.spawn_nicely user_label end end + when :compose + ComposeMode.spawn_nicely + when :poll + reporting_thread("user-invoked poll") { PollManager.poll } + when :recall_draft + case Index.num_results_for :label => :draft + when 0 + bm.flash "No draft messages." + when 1 + m = nil + Index.each_id_by_date(:label => :draft) { |mid, builder| m = builder.call } + r = ResumeMode.new(m) + BufferManager.spawn "Edit message", r + r.edit_message + else + b, new = BufferManager.spawn_unless_exists("All drafts") { LabelSearchResultsMode.new [:draft] } + b.mode.load_threads :num => b.content_height if new + end + when :nothing, InputSequenceAborted + when :redraw + bm.completely_redraw_screen + else + bm.flash "Unknown keypress '#{c.to_character}' for #{bm.focus_buf.mode.name}." end + + bm.draw_screen end - bm.kill_all_buffers - Redwood::LabelManager.save - Redwood::ContactManager.save + + bm.kill_all_buffers if SuicideManager.die? rescue Exception => e - $exception ||= e + $exceptions << [e, "main"] ensure + unless $opts[:no_threads] + PollManager.stop if PollManager.instantiated? + SuicideManager.stop if PollManager.instantiated? + Index.stop_lock_update_thread + end + + Redwood::finish stop_cursing -end + Redwood::log "stopped cursing" -Index.save unless $exception # TODO: think about this - -if $exception - case $exception - when IndexError - $stderr.puts <