Skip to content
This repository has been archived by the owner on Feb 1, 2019. It is now read-only.

Commit

Permalink
coalals.langserver: Add support for textDocument/formatting
Browse files Browse the repository at this point in the history
Update langserver to support a formatting request types. Currently
formatting type requests fixes any code it can irrespective of the
nature. Also, updates tests to check for documentFormattingProvider.
  • Loading branch information
ksdme committed Jul 5, 2018
1 parent 7b4d59d commit 8e75ead
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 1 deletion.
41 changes: 41 additions & 0 deletions coalals/langserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from jsonrpc.dispatchers import MethodDispatcher
from jsonrpc.streams import JsonRpcStreamWriter, JsonRpcStreamReader
from .results.diagnostics import Diagnostics
from .results.fixes import coalaPatch, TextEdits
from .interface import coalaWrapper
from .utils.files import UriUtils, FileProxy, FileProxyMap

Expand Down Expand Up @@ -70,6 +71,7 @@ def __init__(self, rx, tx):
self._capabilities = {
'capabilities': {
'textDocumentSync': 1,
'documentFormattingProvider': 1,
}
}

Expand Down Expand Up @@ -233,6 +235,45 @@ def m_text_document__did_change(self, **params):
# handling mechanism should be handled in FileProxy's
# update method

def m_text_document__formatting(self, **params):
"""
textDocument/formatting is a request. A formatting
request is raised from the editor. The server should
intend to fix all the indentation and spacing like
issues.
:param params:
The parameters passed during the request.
"""
logger.info('Responding to formatting request')

text_document = params['textDocument']
filename = self._text_document_to_name(text_document)

# If the file does not exist in the proxy map
# discard the request, it should didOpen first
proxy = self._proxy_map.get(filename)
if proxy is None:
return

def _internal_formatter():
result = self._coala.p_analyse_file(proxy, force=False)
if result is False: # pragma: no cover
logging.info('Failed analysis on %s', proxy.filename)
return

# wait for returns
coala_json = result.result()
fixes = Diagnostics.from_coala_json(coala_json)

# send diagnostic warnings found during analysis
self.send_diagnostics(proxy.filename, fixes)

text_edits = fixes.fixes_to_text_edits(proxy)
return list(text_edits.get())

return _internal_formatter

def m_text_document__did_close(self, **params):
"""
textDocument/didClose is dispatched by the client to the
Expand Down
71 changes: 70 additions & 1 deletion tests/tests_coalals/test_langserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,29 @@

@pytest.fixture
def file_langserver(monkeypatch):
DummyProcessPoolExecutor.on_submit = None

with monkeypatch.context() as patch:
patch.setattr('coalals.concurrency.ProcessPoolExecutor',
DummyProcessPoolExecutor)

file = TemporaryFile()
langserver = LangServer(file, file)

return (file, langserver)


@pytest.fixture
def file_langserver_deep(monkeypatch):
DummyProcessPoolExecutor.on_submit = None

with monkeypatch.context() as patch:
patch.setattr('coalals.concurrency.ProcessPoolExecutor',
DummyProcessPoolExecutor)
# concurrent.futures maintains the same API for PoolExecutor's
# hence, reusing DummyProcessPoolExecutor for ThreadPoolExecutor
patch.setattr('jsonrpc.endpoint.futures.ThreadPoolExecutor',
DummyProcessPoolExecutor)

file = TemporaryFile()
langserver = LangServer(file, file)
Expand Down Expand Up @@ -46,7 +66,9 @@ def verify_docsync_respone(verify_response):
def _internal(file, langserver):
def consumer(file, response, passed):
assert response is not None
assert response['result']['capabilities']['textDocumentSync'] == 1
capabilities = response['result']['capabilities']
assert capabilities['textDocumentSync'] == 1
assert capabilities['documentFormattingProvider'] == 1

file.close()
passed[0] = True
Expand Down Expand Up @@ -448,6 +470,53 @@ def test_langserver_did_save_failed_job(monkeypatch):
assert_callback_not_called(file)


@pytest.mark.parametrize('will_respond', [True, False])
def test_langserver_document_formatting(will_respond,
file_langserver_deep,
verify_response):
file, langserver = file_langserver_deep

code_sample_path = url('failure3.py', True)
code_sample_name = str(code_sample_path)
proxy = FileProxy(code_sample_name)

# it should fail if the file is not open
# in the editor by extension is not in the
# proxy map.
if will_respond is True:
langserver._proxy_map.add(proxy)

request = {
'method': 'textDocument/formatting',
'params': {
'textDocument': {
'uri': code_sample_path.as_uri(),
},

'options': {
'tabSize': 4,
'insertSpaces': True,
},
},
'jsonrpc': '2.0',
'id': 1244,
}

langserver._endpoint.consume(request)

def consumer(file, response, passed):
if will_respond is False:
passed[0] = True
return

elif 'id' in response:
for text_edit in response['result']:
assert text_edit['newText']
passed[0] = True

verify_response(file, langserver, consumer)


@pytest.mark.parametrize('name,add', [
('one', True),
('two', False)])
Expand Down

0 comments on commit 8e75ead

Please sign in to comment.