From mboxrd@z Thu Jan 1 00:00:00 1970 From: stipim@rpi.edu (Michael John Stipicevic) Date: Mon, 16 Feb 2009 01:27:00 -0500 Subject: [sup-talk] (no subject) Message-ID: <200902160627.n1G6R0ZG003126@rmtacc26-la.rcs.rpi.edu> >From 9b863d8c86226b3d148e56060092556e2b13a5df Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:39:50 -0500 Subject: [PATCH] Added UndoManager class The UndoManager keeps a list of lambdas that undo actions. It's designed to be used by keypress hooks. It is initialized in the main sup thread along with UpdateManager, etc. --- lib/sup.rb | 2 + lib/sup/modes/thread-index-mode.rb | 6 +++++ lib/sup/undo.rb | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 0 deletions(-) create mode 100644 lib/sup/undo.rb diff --git a/lib/sup.rb b/lib/sup.rb index 93369a5..eda673b 100644 --- a/lib/sup.rb +++ b/lib/sup.rb @@ -125,6 +125,7 @@ module Redwood Redwood::PollManager.new Redwood::SuicideManager.new Redwood::SUICIDE_FN Redwood::CryptoManager.new + Redwood::UndoManager.new end def finish @@ -281,6 +282,7 @@ require "sup/tagger" require "sup/draft" require "sup/poll" require "sup/crypto" +require "sup/undo" require "sup/horizontal-selector" require "sup/modes/line-cursor-mode" require "sup/modes/help-mode" diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 4de4613..ee30284 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -44,6 +44,7 @@ EOS k.add :tag_matching, "Tag matching threads", 'g' 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", '#' + k.add :undo, "Undo the previous action", 'u' end def initialize hidden_labels=[], load_thread_opts={} @@ -83,6 +84,7 @@ EOS def reload drop_all_threads + UndoManager.clear BufferManager.draw_screen load_threads :num => buffer.content_height end @@ -208,6 +210,10 @@ EOS add_or_unhide m end + def undo + UndoManager.undo + end + def update @mutex.synchronize do ## let's see you do THIS in python diff --git a/lib/sup/undo.rb b/lib/sup/undo.rb new file mode 100644 index 0000000..250433d --- /dev/null +++ b/lib/sup/undo.rb @@ -0,0 +1,42 @@ +module Redwood + +## Implements a single undo list for the Sup instance +## +## The basic idea is to keep a list of lambdas to undo +## things. When an action is called (such as 'archive'), +## a lambda is registered with UndoManager that will +## undo the archival action + +class UndoManager + include Singleton + + def initialize + @@actionlist = [] + self.class.i_am_the_instance self + end + + def register desc, actions + actions = [actions] unless actions.is_a?Array + raise StandardError, "when would I need to undo 'nothing?'" unless actions.length > 0 + Redwood::log "registering #{actions.length} actions: #{desc}" + @@actionlist.push({:desc => desc, :actions => actions}) + end + + def undo + unless @@actionlist.length == 0 then + actionset = @@actionlist.pop + Redwood::log "undoing #{actionset[:desc]}..." + actionset[:actions].each{|action| + action.call + } + BufferManager.flash "undid #{actionset[:desc]}" + else + BufferManager.flash "nothing more to undo" + end + end + + def clear + @@actionlist = [] + end +end +end -- 1.5.3 >From 61a256d09ec8091e5ab44cc4e0e5c9c24c81a4cf Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:40:39 -0500 Subject: [PATCH] Added undo for archive --- lib/sup/modes/inbox-mode.rb | 35 +++++++++++++++++++++++++++++++++++ lib/sup/modes/thread-index-mode.rb | 21 +++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/sup/modes/inbox-mode.rb b/lib/sup/modes/inbox-mode.rb index 559892d..21eb9ac 100644 --- a/lib/sup/modes/inbox-mode.rb +++ b/lib/sup/modes/inbox-mode.rb @@ -26,12 +26,28 @@ class InboxMode < ThreadIndexMode def archive return unless cursor_thread + thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread + + undo = lambda { + thread.apply_label :inbox + add_or_unhide thread.first + } + UndoManager.register("archiving thread #{thread.first.id}", undo) + cursor_thread.remove_label :inbox hide_thread cursor_thread regen_text end def multi_archive threads + undo = threads.map {|t| + lambda{ + t.apply_label :inbox + add_or_unhide t.first + }} + UndoManager.register("archiving #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda {regen_text} ) + threads.each do |t| t.remove_label :inbox hide_thread t @@ -41,6 +57,15 @@ class InboxMode < ThreadIndexMode def read_and_archive return unless cursor_thread + thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread + + undo = lambda { + thread.apply_label :inbox + thread.apply_label :unread + add_or_unhide thread.first + } + UndoManager.register("reading and archiving thread ", undo) + cursor_thread.remove_label :unread cursor_thread.remove_label :inbox hide_thread cursor_thread @@ -48,6 +73,16 @@ class InboxMode < ThreadIndexMode end def multi_read_and_archive threads + undo = threads.map {|t| + lambda { + t.apply_label :inbox + t.apply_label :unread + add_or_unhide t.first + } + } + UndoManager.register("reading and archiving #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda {regen_text}) + threads.each do |t| t.remove_label :unread t.remove_label :inbox diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index ee30284..120acad 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -259,13 +259,27 @@ EOS end def actually_toggle_archived t + thread = t + pos = curpos if t.has_label? :inbox t.remove_label :inbox + undo = lambda { + thread.apply_label :inbox + update_text_for_line pos + UpdateManager.relay self,:unarchived, thread.first + } UpdateManager.relay self, :archived, t.first else t.apply_label :inbox + undo = lambda { + thread.remove_label :inbox + update_text_for_line pos + UpdateManager.relay self, :unarchived, thread.first + } UpdateManager.relay self, :unarchived, t.first end + + return undo end def actually_toggle_spammed t @@ -290,12 +304,15 @@ EOS def toggle_archived t = cursor_thread or return - actually_toggle_archived t + undo = [actually_toggle_archived(t), lambda {self.update_text_for_line curpos}] + UndoManager.register("deleting/undeleting thread #{t.first.id}",undo) update_text_for_line curpos end def multi_toggle_archived threads - threads.each { |t| actually_toggle_archived t } + undo = threads.map { |t| actually_toggle_archived t} + UndoManager.register("deleting/undeleting #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda {self.regen_text}) regen_text end -- 1.5.3 >From e42299ce17ed7c12989d0c8a6dea2ed100921e4a Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:03:57 -0500 Subject: [PATCH] Added undo for starring --- lib/sup/modes/thread-index-mode.rb | 21 +++++++++++++++++++-- 1 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 120acad..62fdb85 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -237,24 +237,41 @@ EOS end def actually_toggle_starred t + thread = t # cargo cult programming + pos = curpos if t.has_label? :starred # if ANY message has a star + undo = lambda { + thread.first.add_label :starred + update_text_for_line pos + UpdateManager.relay self, :starred, thread.first + } t.remove_label :starred # remove from all UpdateManager.relay self, :unstarred, t.first else + undo = lambda { + thread.remove_label :starred + update_text_for_line pos + UpdateManager.relay self, :unstarred, thread.first + } t.first.add_label :starred # add only to first UpdateManager.relay self, :starred, t.first end + + return undo end def toggle_starred t = cursor_thread or return - actually_toggle_starred t + undo = actually_toggle_starred t + UndoManager.register("starring/unstarring thread #{t.first.id}",undo) update_text_for_line curpos cursor_down end def multi_toggle_starred threads - threads.each { |t| actually_toggle_starred t } + undo = threads.map { |t| actually_toggle_starred t } + UndoManager.register("starring/unstarring #{threads.size} #{threads.size.pluralize 'thread'}", + undo) regen_text end -- 1.5.3 >From 31bb0fd8f6e701107ce79ad2dbd9d42da4635742 Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:06:36 -0500 Subject: [PATCH] Added undo for spam --- lib/sup/modes/thread-index-mode.rb | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 62fdb85..1e02b5b 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -300,13 +300,28 @@ EOS end def actually_toggle_spammed t + thread = t if t.has_label? :spam + undo = lambda { + thread.apply_label :spam + self.hide_thread thread + UpdateManager.relay self,:spammed, thread.first + } t.remove_label :spam + add_or_unhide t.first UpdateManager.relay self, :unspammed, t.first else + undo = lambda { + thread.remove_label :spam + add_or_unhide thread.first + UpdateManager.relay self,:unspammed, thread.first + } t.apply_label :spam + hide_thread t UpdateManager.relay self, :spammed, t.first end + + return undo end def actually_toggle_deleted t @@ -390,10 +405,9 @@ EOS ## see deleted or spam emails, and when you undelete or unspam them ## you also want them to disappear immediately. def multi_toggle_spam threads - threads.each do |t| - actually_toggle_spammed t - hide_thread t - end + undo = threads.map{ |t| actually_toggle_spammed t} + UndoManager.register("marking/unmarking #{threads.size} #{threads.size.pluralize 'thread'} as spam", + undo << lambda {self.regen_text}) regen_text end -- 1.5.3 >From d1b5ff3d022e0e6aeabf410b0778fd11a5449ed0 Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:08:03 -0500 Subject: [PATCH] Added undo for thread deletion --- lib/sup/modes/thread-index-mode.rb | 21 +++++++++++++++++---- 1 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 1e02b5b..ae7c299 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -326,12 +326,26 @@ EOS def actually_toggle_deleted t if t.has_label? :deleted + undo = lambda { + t.apply_label :deleted + hide_thread t + UpdateManager.relay self, :deleted, t.first + } t.remove_label :deleted + add_or_unhide t.first UpdateManager.relay self, :undeleted, t.first else + undo = lambda { + t.remove_label :deleted + add_or_unhide t.first + UpdateManager.relay self, :undeleted, t.first + } t.apply_label :deleted + hide_thread t UpdateManager.relay self, :deleted, t.first end + + return undo end def toggle_archived @@ -418,10 +432,9 @@ EOS ## see comment for multi_toggle_spam def multi_toggle_deleted threads - threads.each do |t| - actually_toggle_deleted t - hide_thread t - end + undo = threads.map{ |t| actually_toggle_deleted t} + UndoManager.register("deleting/undeleting #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda {regen_text}) regen_text end -- 1.5.3 >From 9a5ac47e979de8030756b88d4e52b6d8a289a25a Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:10:32 -0500 Subject: [PATCH] Added undo for delete thread --- lib/sup/modes/thread-index-mode.rb | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index ae7c299..159839d 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -443,11 +443,18 @@ EOS multi_kill [t] end + ## m-m-m-m-MULTI-KILL def multi_kill threads - threads.each do |t| + undo = threads.map do |t| t.apply_label :killed hide_thread t + thread = t + lambda { thread.remove_label :killed + add_or_unhide thread.first + } end + UndoManager.register("killing #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda {regen_text}) regen_text BufferManager.flash "#{threads.size.pluralize 'Thread'} killed." end -- 1.5.3 >From 1fd41c30189db832abb54f1cda416d0aa624e028 Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:11:28 -0500 Subject: [PATCH] Added undo for label edit --- lib/sup/modes/thread-index-mode.rb | 27 +++++++++++++++++++++++++-- 1 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/sup/modes/thread-index-mode.rb b/lib/sup/modes/thread-index-mode.rb index 159839d..f28302b 100644 --- a/lib/sup/modes/thread-index-mode.rb +++ b/lib/sup/modes/thread-index-mode.rb @@ -509,6 +509,10 @@ EOS def edit_labels thread = cursor_thread or return speciall = (@hidden_labels + LabelManager::RESERVED_LABELS).uniq + + old_labels = thread.labels + pos = curpos + keepl, modifyl = thread.labels.partition { |t| speciall.member? t } user_labels = BufferManager.ask_for_labels :label, "Labels for thread: ", modifyl, @hidden_labels @@ -517,6 +521,15 @@ EOS thread.labels = keepl + user_labels user_labels.each { |l| LabelManager << l } update_text_for_line curpos + + undo = lambda{ + thread.labels = old_labels + update_text_for_line pos + UpdateManager.relay self, :labeled, thread.first + } + + UndoManager.register("labeling thread #{thread.first.id}", undo) + UpdateManager.relay self, :labeled, thread.first end @@ -526,8 +539,18 @@ EOS 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 } + undo = threads.map { |t| old_labels = t.labels + user_labels.each { |l| t.apply_label l } + ## UpdateManager or some other regresh mechanism? + UpdateManager.relay self, :labeled, t.first + lambda { + t.labels = old_labels + UpdateManager.relay self, :labeled, t.first + } + } + user_labels.each { |l| LabelManager << l } + UndoManager.register("labeling #{threads.size} #{threads.size.pluralize 'thread'}", + undo << lambda { regen_text}) else BufferManager.flash "'#{hl}' is a reserved label!" end -- 1.5.3 >From e7abf80a590aa2f2de35343fceecea9deae41193 Mon Sep 17 00:00:00 2001 From: Mike Stipicevic Date: Mon, 16 Feb 2009 00:11:46 -0500 Subject: [PATCH] Changed README to reflect addition of undo --- README.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/README.txt b/README.txt index 1b2b516..05349d7 100644 --- a/README.txt +++ b/README.txt @@ -80,7 +80,7 @@ Current limitations which will be fixed: - Unix-centrism in MIME attachment handling and in sendmail invocation. -- Several obvious missing features, like undo, filters / saved +- Several obvious missing features, like filters / saved searches, message annotations, etc. == SYNOPSYS: -- 1.5.3