Repository: spyder-ide/spyder

Issue:
Go to definition in the Editor stopped working after the introspection services migration to use the LSP
## Problem Description

Go to definition (Ctrl-G) in the Editor stopped working after PR #4751 was merged.

A minor comment first: the `lsp_client_python.log` file is taking forever to build and if something introspection related is done while the file is being built, everything seems to break (help, go to definition and code style warnings).

I think the reason that go to definition has stopped working is that there is an error in the path of the file that the language server is returning to Spyder in [handle_go_to_definition](https://github.com/spyder-ide/spyder/blob/master/spyder/widgets/sourcecode/codeeditor.py#L956). An extra `/` is added at the beginning and the disk name is not capitalized.

For example, let's say that I Ctrl-G [GoToLineDialog](https://github.com/spyder-ide/spyder/blob/master/spyder/widgets/sourcecode/codeeditor.py#L1682) on line 1682 of the file `codeeditor.py`. This file is located on my computer at `C:\Users\User\spyder\spyder\widgets\sourcecode\codeeditor.py`.

The `position['params']` that is returned to [handle_go_to_definition](https://github.com/spyder-ide/spyder/blob/master/spyder/widgets/sourcecode/codeeditor.py#L956) is:

```python
{'uri': 'file:///c:/Users/User/spyder/spyder/widgets/sourcecode/codeeditor.py', 
 'range': {'start': {'line': 102, 'character': 6}, 'end': {'line': 102, 'character': 20}},
 'file': '/c:/Users/User/spyder/spyder/widgets/sourcecode/codeeditor.py'
}
```
So as you can see, the value stored for the file is `'/c:/Users/User/spyder/spyder/widgets/sourcecode/codeeditor.py'` instead of `C:\Users\User\spyder\spyder\widgets\sourcecode\codeeditor.py`, the value that is stored in `CodeEditor.filename`.

If I replace [handle_go_to_definition](https://github.com/spyder-ide/spyder/blob/master/spyder/widgets/sourcecode/codeeditor.py#L956) by:

```python
    @handles(LSPRequestTypes.DOCUMENT_DEFINITION)
    def handle_go_to_definition(self, position):
        position = position['params']
        if position is not None:
            def_range = position['range']
            start = def_range['start']
            position_file = osp.normpath(position['file'][1:])
            if osp.normpath(self.filename) == position_file:
                self.go_to_line(start['line'] + 1, start['character'],
                                None, word=None)
            else:
                self.go_to_definition.emit(position_file, start['line'] + 1,
                                           start['character'])
```

to remove the extra `\` and normalize the paths before comparing them, then the go to definition feature is working again as expected.


## 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 version: Spyder 4.0.0.dev0
* Python version: Python 3.6.5 64bits
* Qt version: Qt 5.9.3
* PyQt version: PyQt5 5.9.2
* Operating System name/version: Windows 

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
pyflakes >=0.6.0  :  1.6.0 (OK)
pycodestyle >=2.3 :  2.3.1 (OK)
pygments >=2.0    :  2.2.0 (OK)
sphinx >=0.6.6    :  1.7.1 (OK)
rope >=0.9.4      :  0.10.7 (OK)
jedi >=0.11.0     :  0.12.1 (OK)
nbconvert >=4.0   :  5.3.1 (OK)
pandas >=0.13.1   :  0.22.0 (OK)
numpy >=1.7       :  1.13.0 (OK)
sympy >=0.7.3     :  1.1.1 (OK)
cython >=0.21     :  0.27.3 (OK)
qtconsole >=4.2.0 :  4.4.0.dev (OK)
IPython >=4.0     :  6.2.1 (OK)
matplotlib >=2.0.0:  2.2.0 (OK)
pylint >=0.25     :  1.8.3 (OK)
```



Discussion:
@jnsebgosselin I think this is a Windows-only issue, thanks for pointing out!
@andfoy is there an easy way to prevent `lsp_client_python.log` from building when running Spyder from `boostrap.py`?
> A minor comment first: the lsp_client_python.log file is taking forever to build

What do you mean by this?
>> A minor comment first: the lsp_client_python.log file is taking forever to build

> What do you mean by this?

Thanks @ccordoba12. The new lsp merge as broken almost completely introspection for me. `Go to definition` is not working as reported here, but also, code analysis is very laggy and buggy. Most often than not, it is simply not working at all.

I was thinking maybe it was because of the `lsp_client_python.log` file that is created in the `.spyder-py3\lsp_logs` every-time I open Spyder. Sometimes, this file is larger than 1Meg. I've joined an example below.

[lsp_client_python.log](https://github.com/spyder-ide/spyder/files/2315931/lsp_client_python.log)

> Go to definition is not working as reported here, but also, code analysis is very laggy and buggy. Most often than not, it is simply not working at all.

Sorry to hear that. The thing is @andfoy and me work on Linux and in our tests code analysis was working well.

> I was thinking maybe it was because of the lsp_client_python.log file that is created in the .spyder-py3\lsp_logs every-time I open Spyder

The file is currently created in `spyder/plugins/editor/client.py`, line `137`. Please try to deactivate it to see what happens.
kk thank you Carlos, I will try that and report back the results.
@ccordoba12 Setting `Dev` to `False` in `client.py` improved things **a lot** for code analysis.

I've seen at some point a `lsp_client_python.log` file of more than 8 Megs! That's a lot of plaintext to process.
Ok, thanks for digging into that one. I'm not using master regularly because I'm still maintaining 3.x.

@andfoy, what should we do about this? 
@ccordoba12 I think we should lower the logging level to Warning, and just in case an user has an issue, instruct her/him to enable full logging on the LSP client
Good idea! Please work on a PR to do that.
https://stackoverflow.com/questions/43911052/urlparse-on-a-windows-file-scheme-uri-leaves-extra-slash-at-start

The method `process_go_to_definition` located at `spyder/plugins/editor/lsp/providers/document.py` needs to be fixed to unlock  `Go to Definition` feature again on Windows :

```python
    @handles(LSPRequestTypes.DOCUMENT_DEFINITION)
    def process_go_to_definition(self, result, req_id):
        if isinstance(result, list):
            if len(result) > 0:
                result = result[0]
                uri = urlparse(result['uri'])
                result['file'] = osp.join(uri.netloc, uri.path)
            else:
                result = None
        if req_id in self.req_reply:
            self.req_reply[req_id].emit(
                LSPRequestTypes.DOCUMENT_DEFINITION,
{'params': result})
```
@jnsebgosselin, could you submit a PR for this? Thanks!
Ok, but a test should be written to cover that and I feel ill equipped to write one.
Yes, I know, but @andfoy can help us with that after the PR is merged. He's going to add tests for the LSP client implementation he created for Spyder this week.
Ok good. In that case, this is a deal. 

Resolving patch:
diff --git a/spyder/plugins/editor/lsp/providers/document.py b/spyder/plugins/editor/lsp/providers/document.py
--- a/spyder/plugins/editor/lsp/providers/document.py
+++ b/spyder/plugins/editor/lsp/providers/document.py
@@ -18,9 +18,11 @@
 if PY2:
     import pathlib2 as pathlib
     from urlparse import urlparse
+    from urllib import url2pathname
 else:
     import pathlib
     from urllib.parse import urlparse
+    from urllib.request import url2pathname
 
 
 def path_as_uri(path):
@@ -179,7 +181,10 @@ def process_go_to_definition(self, result, req_id):
             if len(result) > 0:
                 result = result[0]
                 uri = urlparse(result['uri'])
-                result['file'] = osp.join(uri.netloc, uri.path)
+                netloc, path = uri.netloc, uri.path
+                # Prepend UNC share notation if we have a UNC path.
+                netloc = '\\\\' + netloc if netloc else netloc
+                result['file'] = url2pathname(netloc + path)
             else:
                 result = None
         if req_id in self.req_reply:


Test patch: