X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=bin%2Fsup;h=a8eaccae0e125460c9cb4213dafbcaae8e8253c2;hb=43ccf339799293ab02e2c69b584ca3fe7bf2fb86;hp=b69530658f146b4e9eb4d8a88d0ce2d4112b6f49;hpb=6b2222c4b3e464ed6b97d2fe23ddf591994f12ae;p=sup diff --git a/bin/sup b/bin/sup old mode 100644 new mode 100755 index b695306..a8eacca --- a/bin/sup +++ b/bin/sup @@ -7,6 +7,20 @@ require 'fileutils' require 'trollop' require "sup" +BIN_VERSION = "git" + +unless Redwood::VERSION == BIN_VERSION + $stderr.puts < String + opt :list_hooks, "List all hooks and descriptions, and quit." + opt :no_threads, "Turn off threading. Helps with debugging. (Necessarily disables background polling for new messages.)" + opt :no_initial_poll, "Don't poll for new messages when starting." + opt :search, "Search for this query upon startup", :type => String + opt :compose, "Compose message to this recipient upon startup", :type => String end +Redwood::HookManager.register "startup", < 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 @@ -52,6 +116,7 @@ def start_cursing Ncurses.noecho Ncurses.cbreak Ncurses.stdscr.keypad 1 + Ncurses.use_default_colors Ncurses.curs_set 0 Ncurses.start_color $cursing = true @@ -76,8 +141,8 @@ rescue Index::LockError => e h.say Index.fancy_lock_error_message_for(e) case h.ask("Should I ask that process to kill itself? ") - when /^\s*y\s*$/i - h.say "Ok, suggesting sepuku..." + when /^\s*y(es)?\s*$/i + h.say "Ok, suggesting seppuku..." FileUtils.touch Redwood::SUICIDE_FN sleep SuicideManager::DELAY * 2 FileUtils.rm_f Redwood::SUICIDE_FN @@ -93,74 +158,29 @@ EOS end begin - extend CanSpawnComposeMode Redwood::start Index.load - if(s = Index.source_for DraftManager.source_name) + if(s = Redwood::SourceManager.source_for DraftManager.source_name) DraftManager.source = s else Redwood::log "no draft source, auto-adding..." - Index.add_source DraftManager.new_source + Redwood::SourceManager.add_source DraftManager.new_source end - if(s = Index.source_for SentManager.source_name) + if(s = Redwood::SourceManager.source_for SentManager.source_uri) SentManager.source = s else - Redwood::log "no sent mail source, auto-adding..." - Index.add_source SentManager.new_source + Redwood::SourceManager.add_source SentManager.default_source end + HookManager.run "startup" + log "starting curses" start_cursing - log "initializing colormap" - Colormap.new do |c| - c.add :status_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLUE, Ncurses::A_BOLD - c.add :index_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK - c.add :index_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :index_starred_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :labellist_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK - c.add :labellist_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :twiddle_color, Ncurses::COLOR_BLUE, Ncurses::COLOR_BLACK - c.add :label_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK - c.add :message_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_GREEN - c.add :alternate_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_BLUE - c.add :missing_message_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_RED - c.add :attachment_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - c.add :cryptosig_valid_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, Ncurses::A_BOLD - c.add :cryptosig_unknown_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - c.add :cryptosig_invalid_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_RED, Ncurses::A_BOLD - c.add :generic_notice_patina_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - c.add :quote_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK - c.add :sig_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK - c.add :quote_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK - c.add :sig_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK - c.add :to_me_color, Ncurses::COLOR_GREEN, Ncurses::COLOR_BLACK - c.add :starred_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :starred_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_GREEN, - Ncurses::A_BOLD - c.add :alternate_starred_patina_color, Ncurses::COLOR_YELLOW, - Ncurses::COLOR_BLUE, Ncurses::A_BOLD - c.add :snippet_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - c.add :option_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK - c.add :tagged_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :draft_notification_color, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK, - Ncurses::A_BOLD - c.add :completion_character_color, Ncurses::COLOR_WHITE, - Ncurses::COLOR_BLACK, Ncurses::A_BOLD - c.add :reply_mode_selected_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK, Ncurses::A_BOLD - c.add :reply_mode_unselected_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - c.add :reply_mode_label_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK - end - - log "initializing buffer manager" bm = BufferManager.new + Colormap.new.populate_colormap log "initializing mail index buffer" imode = InboxMode.new @@ -171,24 +191,22 @@ begin bm.draw_screen - begin - Index.usual_sources.each { |s| s.check } - rescue SourceError - # do nothing! we'll report it at the next step - end - Redwood::report_broken_sources - - Index.usual_sources.each do |s| - reporting_thread do + Redwood::SourceManager.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 if s.respond_to? :connect - end + end + end unless $opts[:no_initial_poll] + + imode.load_threads :num => ibuf.content_height, :when_done => lambda { |num| reporting_thread("poll after loading inbox") { sleep 1; PollManager.poll } unless $opts[:no_threads] || $opts[:no_initial_poll] } - imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread { sleep 1; PollManager.poll } unless $opts[:no_threads] } + if $opts[:compose] + ComposeMode.spawn_nicely :to_default => $opts[:compose] + end unless $opts[:no_threads] PollManager.start @@ -200,88 +218,100 @@ begin SearchResultsMode.spawn_from_query $opts[:search] end - until $exception || SuicideManager.die? - c = Ncurses.nonblocking_getch + until Redwood::exceptions.nonempty? || SuicideManager.die? + c = + begin + Ncurses.nonblocking_getch + rescue Exception => e + if e.is_a?(Interrupt) + raise if BufferManager.ask_yes_or_no("Die ungracefully now?") + bm.draw_screen + nil + end + end next unless c bm.erase_flash - unless bm.handle_input(c) - x = global_keymap.action_for c - case x - 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 = bm.spawn_unless_exists("Contact List") { ContactListMode.new } - b.mode.load_in_background - when :search - query = BufferManager.ask :search, "query: " - 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 - user_label = - case user_label - when nil, /^\s*$/ - bm.spawn_modal("Label list", LabelListMode.new) if user_label && user_label.empty? - else - LabelManager.label_for user_label - end - - case user_label - when nil - when :inbox - BufferManager.raise_to_front InboxMode.instance.buffer + action = + begin + if bm.handle_input c + :nothing else - b = BufferManager.spawn_unless_exists("All threads with label '#{user_label}'") do - mode = LabelSearchResultsMode.new([user_label]) - end - b.mode.load_threads :num => b.content_height + bm.resolve_input_with_keymap c, global_keymap end - - when :compose - spawn_compose_mode - when :poll - reporting_thread { 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 + rescue InputSequenceAborted + :nothing + end + case action + when :quit_now + break if bm.kill_all_buffers_safely + when :quit_ask + if bm.ask_yes_or_no "Really quit?" + break if bm.kill_all_buffers_safely + end + 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", :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 + query = BufferManager.ask :search, "search all messages: " + next unless query && query !~ /^\s*$/ + SearchResultsMode.spawn_from_query query + when :search_unread + SearchResultsMode.spawn_from_query "is:unread" + when :list_labels + 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? + bm.spawn_unless_exists("Label list") { LabelListMode.new } if user_label && user_label.empty? else - b = BufferManager.spawn_unless_exists("All drafts") do - mode = LabelSearchResultsMode.new [:draft] - end - b.mode.load_threads :num => b.content_height + LabelSearchResultsMode.spawn_nicely user_label end - when :nothing - when :redraw - bm.completely_redraw_screen + 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 - bm.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}." + b, new = BufferManager.spawn_unless_exists("All drafts") { LabelSearchResultsMode.new [:draft] } + b.mode.load_threads :num => b.content_height if new end + when :show_inbox + BufferManager.raise_to_front ibuf + 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 if SuicideManager.die? rescue Exception => e - $exception ||= e + Redwood::record_exception e, "main" ensure unless $opts[:no_threads] PollManager.stop if PollManager.instantiated? @@ -289,16 +319,17 @@ ensure Index.stop_lock_update_thread end + HookManager.run "shutdown" + Redwood::finish stop_cursing Redwood::log "stopped cursing" if SuicideManager.instantiated? && SuicideManager.die? - Redwood::log "I've been ordered to commit sepuku. I obey!" + Redwood::log "I've been ordered to commit seppuku. I obey!" end - case $exception - when nil + if Redwood::exceptions.empty? Redwood::log "no fatal errors. good job, william." Index.save else @@ -308,23 +339,29 @@ ensure Index.unlock end -if $exception +unless Redwood::exceptions.empty? + File.open(File.join(BASE_DIR, "exception-log.txt"), "w") do |f| + Redwood::exceptions.each do |e, name| + f.puts "--- #{e.class.name} from thread: #{name}" + f.puts e.message, e.backtrace + end + end $stderr.puts <