Repository: spyder-ide/spyder

Issue:
Find in files gives error when searching in just one file
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->

* Menu - Search - Find in files
* {searching for some string in ALL files in current dir}
* Then change string for searching and search in just one file
* This error appears, Spyder does not freeze, but does not show found occurences of a string

### Traceback
```python-traceback
Traceback (most recent call last):
  File "C:\PROG2\PYTHON\python-3.10.5.amd64\lib\site-packages\spyder\plugins\findinfiles\widgets\results_browser.py", line 263, in append_file_result
    self.files[filename] = item = FileMatchItem(
  File "C:\PROG2\PYTHON\python-3.10.5.amd64\lib\site-packages\spyder\plugins\findinfiles\widgets\results_browser.py", line 85, in __init__
    rel_dirname = dirname.split(path)[1]
IndexError: list index out of range
```

## Versions

* Spyder version: 5.4.0.dev0  (pip)
* Python version: 3.10.5 64-bit
* Qt version: 5.15.2
* PyQt5 version: 5.15.6
* Operating System: Windows 10

### Dependencies

```
# Mandatory:
atomicwrites >=1.2.0          :  1.4.0 (OK)
chardet >=2.0.0               :  4.0.0 (OK)
cloudpickle >=0.5.0           :  2.1.0 (OK)
cookiecutter >=1.6.0          :  2.1.1 (OK)
diff_match_patch >=20181111   :  20200713 (OK)
intervaltree >=3.0.2          :  3.0.2 (OK)
IPython >=7.31.1;<8.0.0       :  7.32.0 (OK)
jedi >=0.17.2;<0.19.0         :  0.18.1 (OK)
jellyfish >=0.7               :  0.9.0 (OK)
jsonschema >=3.2.0            :  4.6.2 (OK)
keyring >=17.0.0              :  23.5.0 (OK)
nbconvert >=4.0               :  6.5.0 (OK)
numpydoc >=0.6.0              :  1.3 (OK)
paramiko >=2.4.0              :  2.8.0 (OK)
parso >=0.7.0;<0.9.0          :  0.8.3 (OK)
pexpect >=4.4.0               :  4.8.0 (OK)
pickleshare >=0.4             :  0.7.5 (OK)
psutil >=5.3                  :  5.9.0 (OK)
pygments >=2.0                :  2.13.0 (OK)
pylint >=2.5.0;<3.0           :  2.14.0 (OK)
pyls_spyder >=0.4.0           :  0.4.0 (OK)
pylsp >=1.4.1;<1.5.0          :  1.4.1 (OK)
pylsp_black >=1.2.0           :  1.2.1 (OK)
qdarkstyle >=3.0.2;<3.1.0     :  3.0.3 (OK)
qstylizer >=0.1.10            :  0.2.1 (OK)
qtawesome >=1.0.2             :  1.1.1 (OK)
qtconsole >=5.3.0;<5.4.0      :  5.3.1 (OK)
qtpy >=2.1.0                  :  2.2.0.dev0 (OK)
rtree >=0.9.7                 :  1.0.0 (OK)
setuptools >=49.6.0           :  65.6.3 (OK)
sphinx >=0.6.6                :  5.0.2 (OK)
spyder_kernels >=2.3.1;<2.4.0 :  2.3.2 (OK)
textdistance >=4.2.0          :  4.2.2 (OK)
three_merge >=0.1.1           :  0.1.1 (OK)
watchdog >=0.10.3             :  2.1.8 (OK)
zmq >=22.1.0                  :  23.2.0 (OK)

# Optional:
cython >=0.21                 :  0.29.30 (OK)
matplotlib >=3.0.0            :  3.5.2 (OK)
numpy >=1.7                   :  1.22.4 (OK)
pandas >=1.1.1                :  1.4.3 (OK)
scipy >=0.17.0                :  1.8.1 (OK)
sympy >=0.7.3                 :  1.10.1 (OK)
```



Discussion:
Hi @mirekslouf thank you for the feedback! This seems like a duplicate of https://github.com/spyder-ide/spyder/issues/17443 Seems like you are running Spyder from the dev source (the version captured in the issue says you are using `Spyder version: 5.4.0.dev0 (pip)`. How did you install Spyder? If you are using Spyder from source, using the latest dev source should give you the fix (`5.5.0.dev0` 59d547acd147398c0e82bef24e0d21cc02781879).

Any other info to help you with the issue is greatly appreciated. Let us know!   
@dalthviz, I think I didn't fix issue #17443 correctly and @mirekslouf reproduction steps helped me to understand why. The problem is `Find in files` is currently broken when searching in a single file. PR #19124 avoided the error reported here, but doesn't allow to display the search results in the pane.

So, I'll remove my previous fix and add a new one that properly addresses the problem.

Resolving patch:
diff --git a/spyder/plugins/findinfiles/widgets/results_browser.py b/spyder/plugins/findinfiles/widgets/results_browser.py
--- a/spyder/plugins/findinfiles/widgets/results_browser.py
+++ b/spyder/plugins/findinfiles/widgets/results_browser.py
@@ -79,9 +79,17 @@ def __init__(self, parent, path, filename, sorting, text_color):
 
         # Get relative dirname according to the path we're searching in.
         dirname = osp.dirname(filename)
-        rel_dirname = dirname.split(path)[1]
-        if rel_dirname.startswith(osp.sep):
-            rel_dirname = rel_dirname[1:]
+
+        # Catch errors when it's not possible to get the relative directory
+        # name. This happens when the user is searching in a single file.
+        # Fixes spyder-ide/spyder#17443 and spyder-ide/spyder#20964
+        try:
+            rel_dirname = dirname.split(path)[1]
+            if rel_dirname.startswith(osp.sep):
+                rel_dirname = rel_dirname[1:]
+        except IndexError:
+            rel_dirname = dirname
+
         self.rel_dirname = rel_dirname
 
         title = (
@@ -257,18 +265,13 @@ def clear_title(self, search_text):
     def append_file_result(self, filename):
         """Real-time update of file items."""
         if len(self.data) < self.max_results:
-            # Catch any error while creating file items.
-            # Fixes spyder-ide/spyder#17443
-            try:
-                item = FileMatchItem(
-                    self,
-                    self.path,
-                    filename,
-                    self.sorting,
-                    self.text_color
-                )
-            except Exception:
-                return
+            item = FileMatchItem(
+                self,
+                self.path,
+                filename,
+                self.sorting,
+                self.text_color
+            )
 
             self.files[filename] = item
 
diff --git a/spyder/plugins/findinfiles/widgets/search_thread.py b/spyder/plugins/findinfiles/widgets/search_thread.py
--- a/spyder/plugins/findinfiles/widgets/search_thread.py
+++ b/spyder/plugins/findinfiles/widgets/search_thread.py
@@ -263,11 +263,14 @@ def find_string_in_file(self, fname):
                             found = line.find(text, found + 1)
                             if found > -1:
                                 break
-
         except IOError as xxx_todo_changeme:
             (_errno, _strerror) = xxx_todo_changeme.args
             self.error_flag = _("permission denied errors were encountered")
 
+        # Process any pending results
+        if self.is_file and self.partial_results:
+            self.process_results()
+
         self.completed = True
 
     def process_results(self):


Test patch:
diff --git a/spyder/plugins/findinfiles/widgets/tests/test_widgets.py b/spyder/plugins/findinfiles/widgets/tests/test_widgets.py
--- a/spyder/plugins/findinfiles/widgets/tests/test_widgets.py
+++ b/spyder/plugins/findinfiles/widgets/tests/test_widgets.py
@@ -649,5 +649,25 @@ def test_max_results(findinfiles, qtbot):
     findinfiles.set_max_results(1000)
 
 
+@flaky(max_runs=5)
+def test_find_in_single_file(findinfiles, qtbot):
+    """
+    Test that find in files works for a single file.
+
+    This a regression test for issues spyder-ide/spyder#17443 and
+    spyder-ide/spyder#20964.
+    """
+    findinfiles.set_search_text("spam")
+    findinfiles.set_file_path(osp.join(LOCATION, "data", 'spam.txt'))
+    findinfiles.path_selection_combo.setCurrentIndex(FILE_PATH)
+
+    with qtbot.waitSignal(findinfiles.sig_finished):
+        findinfiles.find()
+
+    matches = process_search_results(findinfiles.result_browser.data)
+    assert list(matches.keys()) == ['spam.txt']
+    assert expected_results()['spam.txt'] == matches['spam.txt']
+
+
 if __name__ == "__main__":
     pytest.main(['-x', osp.basename(__file__), '-v', '-rw'])