Repository: spyder-ide/spyder

Issue:
Cannot search text in Help pane
## Searching in help pane doesn't work
1. Make sure some documentation is showing in the help pane
2. Click on the documentation so it's focused
3. Press `Ctrl+f`
4. Type something in the search box

**Expected output**
should scroll to and highlight the first instance of matching text in the documentation.

**What I see instead**
Upon pressing `Ctrl+f` I see this in the internal console:

```
Traceback (most recent call last):
  File "/home/drmccloy/Builds/spyder/spyderlib/widgets/findreplace.py", line 203, in show
    text = self.editor.get_selected_text()
AttributeError: 'FrameWebView' object has no attribute 'get_selected_text'
```

Upon typing anything in the search box I see this:

```
Traceback (most recent call last):
  File "/home/drmccloy/Builds/spyder/spyderlib/widgets/findreplace.py", line 295, in text_has_been_edited
    self.find(changed=True, forward=True, start_highlight_timer=True)
  File "/home/drmccloy/Builds/spyder/spyderlib/widgets/findreplace.py", line 322, in find
    found = self.editor.find_text(text, changed, forward, case=case,
AttributeError: 'FrameWebView' object has no attribute 'find_text'
```
## Versions and main components
- Spyder 3.0.0dev (Commit: eb840fe) 
- Python 2.7.6 64bits, Qt 4.8.6, PyQt4 (API v2) 4.10.4 on Linux
## Dependencies

jedi >=0.8.1    :  0.9.0 (OK)
matplotlib >=1.0:  1.5.1+1643.g0423430 (OK)
nbconvert >=4.0 :  4.2.0 (OK)
numpy >=1.7     :  1.12.0.dev0+2af06c8 (OK)
pandas >=0.13.1 :  0.18.0+104.g1c8816f (OK)
pep8 >=0.6      :  1.7.0 (OK)
psutil >=0.3    :  1.2.1 (OK)
pyflakes >=0.5.0:  1.1.0 (OK)
pygments >=1.6  :  2.1.3 (OK)
pylint >=0.25   :  1.5.5 (OK)
qtconsole >=4.0 :  4.2.1 (OK)
rope >=0.9.4    :  0.10.3 (OK)
sphinx >=0.6.6  :  1.5a0 (OK)
sympy >=0.7.3   :  None (NOK)



Discussion:
may or may not be related to #2458 

Thanks for reporting. We'll be sure to address this problem before we release Spyder 3.0 :-)

I can reproduce this problem and I'll fix it in Spyder 3.0 beta4


Resolving patch:
diff --git a/spyderlib/plugins/help.py b/spyderlib/plugins/help.py
--- a/spyderlib/plugins/help.py
+++ b/spyderlib/plugins/help.py
@@ -185,7 +185,7 @@ def __init__(self, parent):
 
         self.webview = FrameWebView(self)
         self.find_widget = FindReplace(self)
-        self.find_widget.set_editor(self.webview)
+        self.find_widget.set_editor(self.webview.web_widget)
         self.find_widget.hide()
 
         layout = QVBoxLayout()
diff --git a/spyderlib/widgets/browser.py b/spyderlib/widgets/browser.py
--- a/spyderlib/widgets/browser.py
+++ b/spyderlib/widgets/browser.py
@@ -65,13 +65,18 @@ def find_text(self, text, changed=True,
                   forward=True, case=False, words=False,
                   regexp=False):
         """Find text"""
-        findflag = QWebEnginePage.FindWrapsAroundDocument
+        if not WEBENGINE:
+            findflag = QWebEnginePage.FindWrapsAroundDocument
+        else:
+            findflag = 0
+
         if not forward:
             findflag = findflag | QWebEnginePage.FindBackward
         if case:
             findflag = findflag | QWebEnginePage.FindCaseSensitively
-        return self.findText(text, findflag)
-    
+
+        return self.findText(text, QWebEnginePage.FindFlags(findflag))
+
     def get_selected_text(self):
         """Return text selected by current text cursor"""
         return self.selectedText()
@@ -290,20 +295,12 @@ def __init__(self, parent):
         else:
             self._webview.linkClicked.connect(self.linkClicked)
 
-    def set_font(self, font, fixed_font=None):
-        self._webview.set_font(font, fixed_font=fixed_font)
-
-    def setHtml(self, html_text, base_url):
-        self._webview.setHtml(html_text, base_url)
-
-    def url(self):
-        return self._webview.url()
-
-    def load(self, url):
-        self._webview.load(url)
+    def __getattr__(self, name):
+        return getattr(self._webview, name)
 
-    def page(self):
-        return self._webview.page()
+    @property
+    def web_widget(self):
+        return self._webview
 
 
 def test():
diff --git a/spyderlib/widgets/findreplace.py b/spyderlib/widgets/findreplace.py
--- a/spyderlib/widgets/findreplace.py
+++ b/spyderlib/widgets/findreplace.py
@@ -41,9 +41,10 @@ def is_position_inf(pos1, pos2):
 class FindReplace(QWidget):
     """Find widget"""
     STYLE = {False: "background-color:rgb(255, 175, 90);",
-             True: ""}
+             True: "",
+             None: ""}
     visibility_changed = Signal(bool)
-    
+
     def __init__(self, parent, enable_replace=False):
         QWidget.__init__(self, parent)
         self.enable_replace = enable_replace
@@ -202,11 +203,16 @@ def show(self):
         if self.editor is not None:
             text = self.editor.get_selected_text()
 
-            # If no text is highlighted for search, use whatever word is under the cursor
+            # If no text is highlighted for search, use whatever word is under
+            # the cursor
             if not text:
-                cursor = self.editor.textCursor()
-                cursor.select(QTextCursor.WordUnderCursor)
-                text = to_text_string(cursor.selectedText())
+                try:
+                    cursor = self.editor.textCursor()
+                    cursor.select(QTextCursor.WordUnderCursor)
+                    text = to_text_string(cursor.selectedText())
+                except AttributeError:
+                    # We can't do this for all widgets, e.g. WebView's
+                    pass
 
             # Now that text value is sorted out, use it for the search
             if text:
@@ -314,6 +320,9 @@ def find(self, changed=True, forward=True,
         text = self.search_text.currentText()
         if len(text) == 0:
             self.search_text.lineEdit().setStyleSheet("")
+            if not self.is_code_editor:
+                # Clears the selection for WebEngine
+                self.editor.find_text('')
             return None
         else:
             case = self.case_button.isChecked()


Test patch: