Repository: spyder-ide/spyder

Issue:
Extra selections should be ordered
## Description of your problem

##### This is more of a suggestion:
Extra selections dict in base.py is a dictionary, but an OrderedDict may be a better option.
Using an ordered dictionary would allow some selections to take precedence over others, ensuring that the last selection added to extra selections is the one which is highlighted.

This would be a solution to [issue 7](https://github.com/spyder-ide/spyder-vim/issues/7) in spyder-vim.

## Versions and main components

* Spyder Version: latest
* Python Version: 3.5.2
* Operating system: Windows 10


Discussion:
Here is somewhere in Spyder where the same issue occurs:
#### Steps:
1. Search for a word which is a part of another word (selection)
2. Place the cursor on the larger word (extra_selections)

This may or may not occur since the dictionary is unordered. Just restart Spyder and repeat the steps.
![find](https://cloud.githubusercontent.com/assets/18713517/21308935/fa02e908-c590-11e6-89ee-3a5c55944923.PNG)
![error](https://cloud.githubusercontent.com/assets/18713517/21308949/058b0404-c591-11e6-8415-0849b7d822b4.PNG)

#### Expected:
The smaller string's extra selection should be given priority over the larger string's selection.
![correct](https://cloud.githubusercontent.com/assets/18713517/21309120/cf789ba0-c591-11e6-87db-1cb2ce3d0754.PNG)


Please go for it. We're glad to receive a PR for this and also improve the state of spyder-vim :-)

Resolving patch:
diff --git a/spyder/widgets/sourcecode/base.py b/spyder/widgets/sourcecode/base.py
--- a/spyder/widgets/sourcecode/base.py
+++ b/spyder/widgets/sourcecode/base.py
@@ -15,6 +15,7 @@
 import os
 import re
 import sys
+from collections import OrderedDict
 
 # Third party imports
 from qtpy.compat import to_qvariant
@@ -229,7 +230,7 @@ def __init__(self, parent=None):
         BaseEditMixin.__init__(self)
         self.setAttribute(Qt.WA_DeleteOnClose)
         
-        self.extra_selections_dict = {}
+        self.extra_selections_dict = OrderedDict()
         
         self.textChanged.connect(self.changed)
         self.cursorPositionChanged.connect(self.cursor_position_changed)
@@ -305,28 +306,40 @@ def set_palette(self, background, foreground):
 
 
     #------Extra selections
+    def extra_selection_length(self, key):
+        selection = self.get_extra_selections(key)
+        if selection:
+            cursor = self.extra_selections_dict[key][0].cursor
+            selection_length = cursor.selectionEnd() - cursor.selectionStart()
+            return selection_length
+        else:
+            return 0
+
     def get_extra_selections(self, key):
         return self.extra_selections_dict.get(key, [])
 
     def set_extra_selections(self, key, extra_selections):
         self.extra_selections_dict[key] = extra_selections
-        
+        self.extra_selections_dict = \
+            OrderedDict(sorted(self.extra_selections_dict.items(),
+                               key=lambda s: self.extra_selection_length(s[0]),
+                               reverse=True))
+
     def update_extra_selections(self):
         extra_selections = []
         for key, extra in list(self.extra_selections_dict.items()):
             if key == 'current_line' or key == 'current_cell':
-                # Python 3 compatibility (weird): current line has to be 
+                # Python 3 compatibility (weird): current line has to be
                 # highlighted first
                 extra_selections = extra + extra_selections
             else:
                 extra_selections += extra
         self.setExtraSelections(extra_selections)
-        
+
     def clear_extra_selections(self, key):
         self.extra_selections_dict[key] = []
         self.update_extra_selections()
-        
-        
+
     def changed(self):
         """Emit changed signal"""
         self.modificationChanged.emit(self.document().isModified())


Test patch: