Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add formatter options support for yapf #946

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pyls/hookspecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ def pyls_folding_range(config, workspace, document):


@hookspec(firstresult=True)
def pyls_format_document(config, workspace, document):
def pyls_format_document(config, workspace, document, options):
pass


@hookspec(firstresult=True)
def pyls_format_range(config, workspace, document, range):
def pyls_format_range(config, workspace, document, range, options):
pass


Expand Down
2 changes: 1 addition & 1 deletion pyls/plugins/autopep8_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF
def pyls_format_document(config, document):
def pyls_format_document(config, document, _options=None):
log.info("Formatting document %s with autopep8", document)
return _format(config, document)

Expand Down
55 changes: 46 additions & 9 deletions pyls/plugins/yapf_format.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
import os
from yapf.yapflib import file_resources
from yapf.yapflib import file_resources, style
from yapf.yapflib.yapf_api import FormatCode
from pyls import hookimpl

log = logging.getLogger(__name__)


@hookimpl
def pyls_format_document(document):
return _format(document)
def pyls_format_document(document, options=None):
return _format(document, options=options)


@hookimpl
def pyls_format_range(document, range): # pylint: disable=redefined-builtin
def pyls_format_range(document, range, options=None): # pylint: disable=redefined-builtin
# First we 'round' the range up/down to full lines only
range['start']['character'] = 0
range['end']['line'] += 1
Expand All @@ -28,17 +28,54 @@ def pyls_format_range(document, range): # pylint: disable=redefined-builtin

# Add 1 for 1-indexing vs LSP's 0-indexing
lines = [(range['start']['line'] + 1, range['end']['line'] + 1)]
return _format(document, lines=lines)
return _format(document, lines=lines, options=options)


def _format(document, lines=None):
def _format(document, lines=None, options=None):
# Get the default styles as a string
# for a preset configuration, i.e. "pep8"
style_config = file_resources.GetDefaultStyleForDir(
os.path.dirname(document.path)
)
if options is not None:
# We have options passed from LSP format request
# let's pass them to the formatter.
# First we want to get a dictionary of the preset style
# to pass instead of a string so that we can modify it
style_config = style.CreateStyleFromConfig(style_config)

use_tabs = style_config['USE_TABS']
indent_width = style_config['INDENT_WIDTH']

if options.get('tabSize') is not None:
indent_width = max(int(options.get('tabSize')), 1)

if options.get('insertSpaces') is not None:
# TODO is it guaranteed to be a boolean, or can it be a string
use_tabs = not options.get('insertSpaces')

if use_tabs:
# Indent width doesn't make sense when using tabs
# the specifications state: "Size of a tab in spaces"
indent_width = 1

style_config['USE_TABS'] = use_tabs
style_config['INDENT_WIDTH'] = indent_width
style_config['CONTINUATION_INDENT_WIDTH'] = indent_width

for style_option, value in options.items():
# Apply arbitrary options passed as formatter options
if style_option not in style_config:
# ignore if it's not a known yapf config
continue

style_config[style_option] = value

new_source, changed = FormatCode(
document.source,
lines=lines,
filename=document.filename,
style_config=file_resources.GetDefaultStyleForDir(
os.path.dirname(document.path)
)
style_config=style_config
)

if not changed:
Expand Down
18 changes: 8 additions & 10 deletions pyls/python_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,11 @@ def document_symbols(self, doc_uri):
def execute_command(self, command, arguments):
return self._hook('pyls_execute_command', command=command, arguments=arguments)

def format_document(self, doc_uri):
return self._hook('pyls_format_document', doc_uri)
def format_document(self, doc_uri, options):
return self._hook('pyls_format_document', doc_uri, options=options)

def format_range(self, doc_uri, range):
return self._hook('pyls_format_range', doc_uri, range=range)
def format_range(self, doc_uri, range, options):
return self._hook('pyls_format_range', doc_uri, range=range, options=options)

def highlight(self, doc_uri, position):
return flatten(self._hook('pyls_document_highlight', doc_uri, position=position)) or None
Expand Down Expand Up @@ -333,19 +333,17 @@ def m_text_document__hover(self, textDocument=None, position=None, **_kwargs):
def m_text_document__document_symbol(self, textDocument=None, **_kwargs):
return self.document_symbols(textDocument['uri'])

def m_text_document__formatting(self, textDocument=None, _options=None, **_kwargs):
# For now we're ignoring formatting options.
return self.format_document(textDocument['uri'])
def m_text_document__formatting(self, textDocument=None, options=None, **_kwargs):
return self.format_document(textDocument['uri'], options)

def m_text_document__rename(self, textDocument=None, position=None, newName=None, **_kwargs):
return self.rename(textDocument['uri'], position, newName)

def m_text_document__folding_range(self, textDocument=None, **_kwargs):
return self.folding(textDocument['uri'])

def m_text_document__range_formatting(self, textDocument=None, range=None, _options=None, **_kwargs):
# Again, we'll ignore formatting options for now.
return self.format_range(textDocument['uri'], range)
def m_text_document__range_formatting(self, textDocument=None, range=None, options=None, **_kwargs):
return self.format_range(textDocument['uri'], range, options)

def m_text_document__references(self, textDocument=None, position=None, context=None, **_kwargs):
exclude_declaration = not context['includeDeclaration']
Expand Down
27 changes: 27 additions & 0 deletions test/plugins/test_yapf_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,33 @@ def test_format(workspace):
assert len(res) == 1
assert res[0]['newText'] == "A = ['h', 'w', 'a']\n\nB = ['h', 'w']\n"

FOUR_SPACE_DOC = """def hello():
pass
"""

def test_format_with_tab_size_option(workspace):
doc = Document(DOC_URI, workspace, FOUR_SPACE_DOC)
res = pyls_format_document(doc, { "tabSize": "8" })

assert len(res) == 1
assert res[0]['newText'] == FOUR_SPACE_DOC.replace(" ", " ")


def test_format_with_insert_spaces_option(workspace):
doc = Document(DOC_URI, workspace, FOUR_SPACE_DOC)
res = pyls_format_document(doc, { "insertSpaces": False })

assert len(res) == 1
assert res[0]['newText'] == FOUR_SPACE_DOC.replace(" ", "\t")


def test_format_with_yapf_specific_option(workspace):
doc = Document(DOC_URI, workspace, FOUR_SPACE_DOC)
res = pyls_format_document(doc, { "USE_TABS": True })

assert len(res) == 1
assert res[0]['newText'] == FOUR_SPACE_DOC.replace(" ", "\t")


def test_range_format(workspace):
doc = Document(DOC_URI, workspace, DOC)
Expand Down