Repository: spyder-ide/spyder

Issue:
URL awereness is broken in latest master
## Problem Description

Ctrl clicking on a URL raises an error.

This was introduced in PR #9572.

https://github.com/spyder-ide/spyder/pull/9572/files#diff-52750ace6e2fd77d54b81a616c01ce5dR3447

A default value for the `full_uri ` variable should be defined at the start of the new `go_to_uri_from_cursor` method to avoid that.

### Paste Traceback/Error Below (if applicable)

```python-traceback
  File "C:\Users\User\spyder\spyder\plugins\editor\widgets\codeeditor.py", line 3663, in mousePressEvent
    if uri:
  File "C:\Users\User\spyder\spyder\plugins\editor\widgets\codeeditor.py", line 3465, in go_to_uri_from_cursor
    full_uri = 'mailto:' + full_uri
UnboundLocalError: local variable 'full_uri' referenced before assignment
```

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder 4.0.0.dev0 (Commit: f1c0e09e2) 
* Python 3.7.1 64-bit | Qt 5.9.6 | PyQt5 5.9.2 | Windows 10 

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
pygments >=2.0     :  2.3.1 (OK)
qdarkstyle >=2.6.4 :  2.8 (OK)
sphinx >=0.6.6     :  1.8.2 (OK)
pyls >=0.19.0;<0.25:  0.24.0 (OK)
nbconvert >=4.0    :  5.3.1 (OK)
pandas >=0.13.1    :  0.23.4 (OK)
numpy >=1.7        :  1.16.3 (OK)
sympy >=0.7.3      :  1.4 (OK)
cython >=0.21      :  0.29.2 (OK)
qtconsole >=4.5.0  :  4.6.0.dev0 (OK)
IPython >=4.0      :  7.5.0 (OK)
matplotlib >=2.0.0 :  3.1.0 (OK)
pylint >=0.25      :  2.2.2 (OK)

```



Discussion:
Thanks for this! I will fix it now and add a test

Resolving patch:
diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py
--- a/spyder/plugins/editor/widgets/codeeditor.py
+++ b/spyder/plugins/editor/widgets/codeeditor.py
@@ -3483,6 +3483,7 @@ def _handle_goto_uri_event(self, pos):
     def go_to_uri_from_cursor(self, uri):
         """Go to url from cursor and defined hover patterns."""
         key = self._last_hover_pattern_key
+        full_uri = uri
         if key in ['file']:
             fname = self._preprocess_file_uri(uri)
 


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_goto.py b/spyder/plugins/editor/widgets/tests/test_goto.py
--- a/spyder/plugins/editor/widgets/tests/test_goto.py
+++ b/spyder/plugins/editor/widgets/tests/test_goto.py
@@ -10,64 +10,78 @@
 import tempfile
 
 # Third party imports
-from qtpy.QtCore import Qt, QPoint
-from qtpy.QtGui import QTextCursor
+from qtpy.QtCore import Qt, QPoint, QTimer
+from qtpy.QtGui import QDesktopServices, QTextCursor
+from qtpy.QtWidgets import QMessageBox
 import pytest
 
 # Local imports
 from spyder.plugins.editor.widgets.tests.test_codeeditor import editorbot
 
 # Constants
+HERE = os.path.abspath(__file__)
 TEST_FOLDER = os.path.abspath(os.path.dirname(__file__))
 _, TEMPFILE_PATH = tempfile.mkstemp()
 TEST_FILES = [os.path.join(TEST_FOLDER, f) for f in
               os.listdir(TEST_FOLDER) if f.endswith('.py')]
 TEST_FILE_ABS = TEST_FILES[0].replace(' ', '%20')
-TEST_FILE_REL = [f for f in os.listdir(TEST_FOLDER) if f.endswith('.py')][0]
+TEST_FILE_REL = 'conftest.py'
 
 
 @pytest.mark.parametrize('params', [
-            # Parameter, Expected output, Full file path (or None if not file)
+            # Parameter, expected output 1, full file path, expected output 2
             # ----------------------------------------------------------------
             # Files that exist with absolute paths
-            ('"file://{}/"\n'.format(TEMPFILE_PATH), TEMPFILE_PATH,
-             TEMPFILE_PATH),
-            ('"file://{}/"\n'.format(TEST_FILE_ABS), TEST_FILE_ABS,
-             TEST_FILE_ABS),
+            ('file://{}\n'.format(TEMPFILE_PATH), 'file://' + TEMPFILE_PATH,
+             TEMPFILE_PATH, 'file://' + TEMPFILE_PATH),
+            ('"file://{}"\n'.format(TEST_FILE_ABS), 'file://' + TEST_FILE_ABS,
+             TEST_FILE_ABS, 'file://' + TEST_FILE_ABS),
             # Files that exist with relative paths
-            ('"file://./{}/"\n'.format(TEST_FILE_REL), TEST_FILE_REL,
-             os.path.join(TEST_FOLDER, TEST_FILE_REL)),
+            ('"file://./{}"\n'.format(TEST_FILE_REL),
+             'file://./' + TEST_FILE_REL,
+             os.path.join(TEST_FOLDER, TEST_FILE_REL),
+             'file://./' + TEST_FILE_REL),
             # Files that do not exist
-            ('"file:///not%20there/"', 'file:///not%20there/',
-             '/not%20there/'),
-            ('"file:///not_there/"', 'file:///not_there/', '/not_there/'),
+            ('"file:///not%20there"', 'file:///not%20there',
+             '/not%20there', 'file:///not%20there'),
+            ('"file:///not_there"', 'file:///not_there', '/not_there',
+             'file:///not_there'),
             # Urls
-            ('" https://google.com"\n', 'https://google.com', None),
-            ('# https://google.com"\n', 'https://google.com', None),
+            ('" https://google.com"\n', 'https://google.com', None,
+             'https://google.com'),
+            ('# https://google.com"\n', 'https://google.com', None,
+             'https://google.com'),
             # Mail to
-            ('" mailto:some@email.com"\n', 'mailto:some@email.com', None),
-            ('# mailto:some@email.com\n', 'mailto:some@email.com', None),
-            ('some@email.com\n', 'some@email.com', None),
-            ('# some@email.com\n', 'some@email.com', None),
+            ('" mailto:some@email.com"\n', 'mailto:some@email.com', None,
+             'mailto:some@email.com'),
+            ('# mailto:some@email.com\n', 'mailto:some@email.com', None,
+             'mailto:some@email.com'),
+            ('some@email.com\n', 'some@email.com', None,
+             'mailto:some@email.com'),
+            ('# some@email.com\n', 'some@email.com', None,
+             'mailto:some@email.com'),
             # Issues
             ('# gl:gitlab-org/gitlab-ce#62529\n',
-             'gl:gitlab-org/gitlab-ce#62529', None),
+             'gl:gitlab-org/gitlab-ce#62529', None,
+             'https://gitlab.com/gitlab-org/gitlab-ce/issues/62529'),
             ('# bb:birkenfeld/pygments-main#1516\n',
-             'bb:birkenfeld/pygments-main#1516', None),
-            ('# gh:spyder-ide/spyder#123\n',
-             'gh:spyder-ide/spyder#123', None),
-            ('# gh:spyder-ide/spyder#123\n',
-             'gh:spyder-ide/spyder#123', None),
-            ('# gh-123\n',
-             'gh-123', None),
+             'bb:birkenfeld/pygments-main#1516', None,
+             'https://bitbucket.org/birkenfeld/pygments-main/issues/1516'),
+            ('# gh:spyder-ide/spyder#123\n', 'gh:spyder-ide/spyder#123', None,
+             'https://github.com/spyder-ide/spyder/issues/123'),
+            ('# gh:spyder-ide/spyder#123\n', 'gh:spyder-ide/spyder#123', None,
+             'https://github.com/spyder-ide/spyder/issues/123'),
+            ('# gh-123\n', 'gh-123', HERE,
+             'https://github.com/spyder-ide/spyder/issues/123'),
         ]
     )
-def test_goto_uri(qtbot, editorbot, params):
+def test_goto_uri(qtbot, editorbot, mocker, params):
     """Test that the uri search is working correctly."""
     _, code_editor = editorbot
     code_editor.show()
+    mocker.patch.object(QDesktopServices, 'openUrl')
 
-    param, expected_output_text, full_file_path = params
+    param, expected_output_1, full_file_path, expected_output_2 = params
     if full_file_path:
         code_editor.filename = full_file_path
 
@@ -90,7 +104,39 @@ def test_goto_uri(qtbot, editorbot, params):
     with qtbot.waitSignal(code_editor.sig_uri_found, timeout=3000) as blocker:
         qtbot.keyPress(code_editor, Qt.Key_Control, delay=500)
         args = blocker.args
-        print(param, expected_output_text)
+        print([param, expected_output_1])
         print([args])
-        output_text = args[0]
-        assert expected_output_text in output_text
+        output_1 = args[0]
+
+        # Tests spyder-ide/spyder#9614
+        output_2 = code_editor.go_to_uri_from_cursor(expected_output_1)
+
+        assert expected_output_1 in output_1
+        assert expected_output_2 == output_2
+
+
+def test_goto_uri_message_box(qtbot, editorbot, mocker):
+    """
+    Test that a message box is displayed when the shorthand issue notation is
+    used (gh-123) indicating the user that the file is not under a repository
+    """
+    _, code_editor = editorbot
+    code_editor.filename = TEMPFILE_PATH
+    code_editor._last_hover_pattern_key = 'issue'
+
+    def interact():
+        msgbox = code_editor.findChild(QMessageBox)
+        assert msgbox
+        qtbot.keyClick(msgbox, Qt.Key_Return)
+
+    timer = QTimer()
+    timer.setSingleShot(True)
+    timer.setInterval(500)
+    timer.timeout.connect(interact)
+    timer.start()
+
+    code_editor.go_to_uri_from_cursor('gh-123')
+
+    code_editor.filename = None
+    code_editor._last_hover_pattern_key = None
+    code_editor._last_hover_pattern_text = None