Repository: spyder-ide/spyder

Issue:
Add shortcut to open last closed tab
Ok, I'm being a bit spoiled with this feature request and Spyder is already insanely awesome.

It would be nice to have a keyboard shortcut to re-open the last tab(s) you just closed.  This would be like Firefox or Chromium where you just hit CTL+SHIFT+T a couple times when you mistakenly close some tabs.



Discussion:
@ccordoba12 @goanpeca I would like to work on this!

Yayy!

@thewhitetulip cool, need some pointers?  @Garrett-R, how far in the history you had in mind? I guess the limit will be the same as we currently store in the last opened files?

What I have in mind is that there will be a function which is triggered when we click the close button, I can get the tab object and store it somewhere, maybe a sqlite file or a plain file and then open a new tab with the same file name, that way we can open the tab even after spyder is closed and opened again. I don't know where to start though

@goanpeca, good question.  Maybe imitate Firefox?  The default limit seems to be 10 tabs.  I'd guess it would be very rare for someone to need the 11th closed tab.

I also think the history can be flushed between sessions as in Firefox.

we can keep unlimited last closed tabs as well :D


Resolving patch:
diff --git a/spyder/config/main.py b/spyder/config/main.py
--- a/spyder/config/main.py
+++ b/spyder/config/main.py
@@ -397,6 +397,7 @@
               'editor/go to previous file': 'Ctrl+Tab',
               'editor/go to next file': 'Ctrl+Shift+Tab',
               'editor/new file': "Ctrl+N",
+              'editor/open last closed':"Ctrl+Shift+T",
               'editor/open file': "Ctrl+O",
               'editor/save file': "Ctrl+S",
               'editor/save all': "Ctrl+Alt+S",
diff --git a/spyder/plugins/editor.py b/spyder/plugins/editor.py
--- a/spyder/plugins/editor.py
+++ b/spyder/plugins/editor.py
@@ -39,7 +39,7 @@
 from spyder.utils import codeanalysis, encoding, programs, sourcecode
 from spyder.utils import icon_manager as ima
 from spyder.utils.introspection.manager import IntrospectionManager
-from spyder.utils.qthelpers import add_actions, create_action
+from spyder.utils.qthelpers import create_action, add_actions
 from spyder.widgets.findreplace import FindReplace
 from spyder.widgets.editor import (EditorMainWindow, EditorSplitter,
                                    EditorStack, Printer)
@@ -631,6 +631,12 @@ def get_plugin_actions(self):
         self.register_shortcut(self.new_action, context="Editor",
                                name="New file", add_sc_to_tip=True)
 
+        self.open_last_closed_action = create_action(self, _("O&pen last closed"),
+                tip=_("Open last closed"),
+                triggered=self.open_last_closed)
+        self.register_shortcut(self.open_last_closed_action, context="Editor",
+                               name="Open last closed")
+        
         self.open_action = create_action(self, _("&Open..."),
                 icon=ima.icon('fileopen'), tip=_("Open file"),
                 triggered=self.load,
@@ -978,6 +984,7 @@ def get_plugin_actions(self):
         file_menu_actions = [self.new_action,
                              None,
                              self.open_action,
+                             self.open_last_closed_action,
                              self.recent_file_menu,
                              None,
                              None,
@@ -1608,7 +1615,7 @@ def __add_recent_file(self, fname):
         self.recent_files.insert(0, fname)
         if len(self.recent_files) > self.get_option('max_recent_files'):
             self.recent_files.pop(-1)
-    
+
     def _clone_file_everywhere(self, finfo):
         """Clone file (*src_editor* widget) in all editorstacks
         Cloning from the first editorstack in which every single new editor
@@ -1942,7 +1949,17 @@ def replace(self):
         """Replace slot"""
         editorstack = self.get_current_editorstack()
         editorstack.find_widget.show_replace()
-
+    
+    def open_last_closed(self):
+        """ Reopens the last closed tab."""
+        editorstack = self.get_current_editorstack()
+        last_closed_files = editorstack.get_last_closed_files()
+        if (len(last_closed_files) > 0):
+            file_to_open = last_closed_files[0]
+            last_closed_files.remove(file_to_open)
+            editorstack.set_last_closed_files(last_closed_files)
+            self.load(file_to_open)
+    
     #------ Explorer widget
     def close_file_from_name(self, filename):
         """Close file from its name"""
diff --git a/spyder/widgets/editor.py b/spyder/widgets/editor.py
--- a/spyder/widgets/editor.py
+++ b/spyder/widgets/editor.py
@@ -423,6 +423,9 @@ def __init__(self, parent, actions):
         # Local shortcuts
         self.shortcuts = self.create_shortcuts()
 
+        #For opening last closed tabs
+        self.last_closed_files = []
+
     def create_shortcuts(self):
         """Create local shortcuts"""
         # --- Configurable shortcuts
@@ -1168,6 +1171,8 @@ def close_file(self, index=None, force=False):
                     new_index -= 1
                 self.set_stack_index(new_index)
 
+            self.add_last_closed_file(finfo.filename)
+
         if self.get_stack_count() == 0 and self.create_new_file_if_empty:
             self.sig_new_file[()].emit()
             return False
@@ -1191,6 +1196,20 @@ def close_all_but_this(self):
         self.close_all_right()
         for i in range(0, self.get_stack_count()-1  ):
             self.close_file(0)
+            
+    def add_last_closed_file(self, fname):
+        """Add to last closed file list."""
+        if fname in self.last_closed_files:
+            self.last_closed_files.remove(fname)
+        self.last_closed_files.insert(0, fname)
+        if len(self.last_closed_files) > 10: 
+            self.last_closed_files.pop(-1)
+
+    def get_last_closed_files(self):
+        return self.last_closed_files
+
+    def set_last_closed_files(self, fnames):
+        self.last_closed_files = fnames
 
     #------ Save
     def save_if_changed(self, cancelable=False, index=None):


Test patch: