Skip to content
This repository has been archived by the owner on Nov 19, 2021. It is now read-only.

Commit

Permalink
Add an option for --single-quote, but strongly prefer double quote in…
Browse files Browse the repository at this point in the history
… readme.
  • Loading branch information
bryanhelmig committed Jun 11, 2018
1 parent b2067aa commit 5540354
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 17 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ black [OPTIONS] [SRC]...
Options:
-l, --line-length INTEGER Where to wrap around. [default: 88]
--single-quote Use single quotes instead of double quotes in
strings except for triple-quoted strings.
--check Don't write the files back, just return the
status. Return code 0 means nothing would
change. Return code 1 means some files would be
Expand Down Expand Up @@ -341,6 +343,9 @@ a one double-quote regardless of fonts and syntax highlighting used.
On top of this, double quotes for strings are consistent with C which
Python interacts a lot with.

> While we strongly recommend double quotes, we also provide a
> `--single-quote` option if you prefer.
On certain keyboard layouts like US English, typing single quotes is
a bit easier than double quotes. The latter requires use of the Shift
key. My recommendation here is to keep using whatever is faster to type
Expand Down
57 changes: 40 additions & 17 deletions black.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from blib2to3.pgen2.parse import ParseError


__version__ = "18.5b1"
__version__ = "18.5z1"
DEFAULT_LINE_LENGTH = 88
CACHE_DIR = Path(user_cache_dir("black", version=__version__))

Expand Down Expand Up @@ -126,6 +126,7 @@ class FileMode(Flag):
AUTO_DETECT = 0
PYTHON36 = 1
PYI = 2
SINGLE_QUOTE = 32


@click.command()
Expand All @@ -137,6 +138,11 @@ class FileMode(Flag):
help="How many character per line to allow.",
show_default=True,
)
@click.option(
"--single-quote",
is_flag=True,
help="Use single quotes instead of double quotes in strings.",
)
@click.option(
"--check",
is_flag=True,
Expand Down Expand Up @@ -195,6 +201,7 @@ def main(
ctx: click.Context,
line_length: int,
check: bool,
single_quote: bool,
diff: bool,
fast: bool,
pyi: bool,
Expand Down Expand Up @@ -227,6 +234,8 @@ def main(
mode |= FileMode.PYTHON36
if pyi:
mode |= FileMode.PYI
if single_quote:
mode |= FileMode.SINGLE_QUOTE
report = Report(check=check, quiet=quiet)
if len(sources) == 0:
out("No paths given. Nothing to do 😴")
Expand Down Expand Up @@ -487,8 +496,11 @@ def format_str(
future_imports = get_future_imports(src_node)
is_pyi = bool(mode & FileMode.PYI)
py36 = bool(mode & FileMode.PYTHON36) or is_python36(src_node)
single_quote = bool(mode & FileMode.SINGLE_QUOTE)
lines = LineGenerator(
remove_u_prefix=py36 or "unicode_literals" in future_imports, is_pyi=is_pyi
remove_u_prefix=py36 or "unicode_literals" in future_imports,
is_pyi=is_pyi,
single_quote=single_quote,
)
elt = EmptyLineTracker(is_pyi=is_pyi)
empty_line = Line()
Expand Down Expand Up @@ -1286,6 +1298,7 @@ class LineGenerator(Visitor[Line]):
"""

is_pyi: bool = False
single_quote: bool = False
current_line: Line = Factory(Line)
remove_u_prefix: bool = False

Expand Down Expand Up @@ -1356,7 +1369,7 @@ def visit_default(self, node: LN) -> Iterator[Line]:
normalize_prefix(node, inside_brackets=any_open_brackets)
if node.type == token.STRING:
normalize_string_prefix(node, remove_u_prefix=self.remove_u_prefix)
normalize_string_quotes(node)
normalize_string_quotes(node, single_quote=self.single_quote)
if node.type not in WHITESPACE:
self.current_line.append(node)
yield from super().visit_default(node)
Expand Down Expand Up @@ -2313,7 +2326,7 @@ def normalize_string_prefix(leaf: Leaf, remove_u_prefix: bool = False) -> None:
leaf.value = f"{new_prefix}{match.group(2)}"


def normalize_string_quotes(leaf: Leaf) -> None:
def normalize_string_quotes(leaf: Leaf, single_quote: bool = False) -> None:
"""Prefer double quotes but only if it doesn't cause more escaping.
Adds or removes backslashes as appropriate. Doesn't parse and fix
Expand All @@ -2322,18 +2335,28 @@ def normalize_string_quotes(leaf: Leaf) -> None:
Note: Mutates its argument.
"""
value = leaf.value.lstrip("furbFURB")
if value[:3] == '"""':

quote_char = '"'
alt_quote_char = "'"
triple_quote_chars = '"""'
alt_triple_quote_chars = "'''"

if single_quote:
quote_char = "'"
alt_quote_char = '"'

if value[:3] == triple_quote_chars:
return

elif value[:3] == "'''":
orig_quote = "'''"
new_quote = '"""'
elif value[0] == '"':
orig_quote = '"'
new_quote = "'"
elif value[:3] == alt_triple_quote_chars:
orig_quote = alt_triple_quote_chars
new_quote = triple_quote_chars
elif value[0] == quote_char:
orig_quote = quote_char
new_quote = alt_quote_char
else:
orig_quote = "'"
new_quote = '"'
orig_quote = alt_quote_char
new_quote = quote_char
first_quote_pos = leaf.value.find(orig_quote)
if first_quote_pos == -1:
return # There's an internal error
Expand All @@ -2360,16 +2383,16 @@ def normalize_string_quotes(leaf: Leaf) -> None:
leaf.value = f"{prefix}{orig_quote}{body}{orig_quote}"
new_body = sub_twice(escaped_orig_quote, rf"\1\2{orig_quote}", new_body)
new_body = sub_twice(unescaped_new_quote, rf"\1\\{new_quote}", new_body)
if new_quote == '"""' and new_body[-1] == '"':
if new_quote == triple_quote_chars and new_body[-1] == triple_quote_chars[0]:
# edge case:
new_body = new_body[:-1] + '\\"'
new_body = new_body[:-1] + "\\" + triple_quote_chars[0]
orig_escape_count = body.count("\\")
new_escape_count = new_body.count("\\")
if new_escape_count > orig_escape_count:
return # Do not introduce more escaping

if new_escape_count == orig_escape_count and orig_quote == '"':
return # Prefer double quotes
if new_escape_count == orig_escape_count and orig_quote == quote_char:
return

leaf.value = f"{prefix}{new_quote}{new_body}{new_quote}"

Expand Down

0 comments on commit 5540354

Please sign in to comment.