Repository: google/yapf

Issue:
Fixing lines with a multi-line string inserts too many lines
Note: I have a fix for this #74.

```
code = '"""\ndocstring\n\n"""\n\nimport blah'
from yapf.yapflib.yapf_api import FormatCode

In [4]: FormatCode(code)
Out[4]: '"""\ndocstring\n\n"""\n\nimport blah\n'

In [5]: FormatCode(code, lines=[(2, 2)])
Out[5]: '"""\ndocstring\n\n"""\n\n\n\n\nimport blah\n'
```

The latter now has (the number of lines in the multi-line string) too many newlines.

*This is an off-by-number-of-lines due to [this value](https://github.com/google/yapf/blob/cfb99aba49789019542ec6cb2b3f7215d1f9a04f/yapf/yapflib/reformatter.py#L105).*

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/2278632/badge)](https://coveralls.io/builds/2278632)

Coverage decreased (-0.05%) to 90.88% when pulling **da1a700cebe8bc3698a501766295befafccaa404 on hayd:fix_74** into **cfb99aba49789019542ec6cb2b3f7215d1f9a04f on google:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/2278632/badge)](https://coveralls.io/builds/2278632)

Coverage decreased (-0.81%) to 90.12% when pulling **da1a700cebe8bc3698a501766295befafccaa404 on hayd:fix_74** into **cfb99aba49789019542ec6cb2b3f7215d1f9a04f on google:master**.


Patch:
diff --git a/plugins/yapf.vim b/plugins/yapf.vim
index cdbb048..3b43104 100644
--- a/plugins/yapf.vim
+++ b/plugins/yapf.vim
@@ -23,7 +23,7 @@
 function! yapf#YAPF() range
   " Determine range to format.
   let l:line_ranges = a:firstline . '-' . a:lastline
-  let l:cmd = 'yapf --lines=' . l:line_ranges
+  let l:cmd = 'env PYTHONPATH=<path_to_srcdir>/yapf <path_to_python>/python -m yapf --lines=' . l:line_ranges
 
   " Call YAPF with the current buffer
   let l:formatted_text = system(l:cmd, join(getline(1, '$'), "\n") . "\n")
diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py
index d8fcd79..6d0f5f2 100644
--- a/yapf/yapflib/reformatter.py
+++ b/yapf/yapflib/reformatter.py
@@ -102,7 +102,10 @@ def _RetainVerticalSpacing(prev_uwline, cur_uwline):
   """Retain all vertical spacing between lines."""
   if not prev_uwline:
     return
-  prev_lineno = prev_uwline.last.lineno
+  if prev_uwline.last.is_string:
+    prev_lineno = prev_uwline.last.lineno + prev_uwline.last.value.count('\n')
+  else:
+    prev_lineno = prev_uwline.last.lineno
   if cur_uwline.first.is_comment:
     cur_lineno = cur_uwline.first.lineno - cur_uwline.first.value.count('\n')
   else:


Test patch:
diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py
index 5ae4e46..fb9f201 100644
--- a/yapftests/yapf_test.py
+++ b/yapftests/yapf_test.py
@@ -503,6 +503,24 @@ class CommandLineTest(unittest.TestCase):
     self.assertIsNone(stderrdata)
     self.assertEqual(reformatted_code.decode('utf-8'), expected_formatted_code)
 
+    unformatted_code = textwrap.dedent(u"""\
+        '''
+        docstring
+
+        '''
+
+        import blah
+        """)
+
+    p = subprocess.Popen(YAPF_BINARY + ['--lines', '2-2'],
+                         stdout=subprocess.PIPE,
+                         stdin=subprocess.PIPE,
+                         stderr=subprocess.STDOUT)
+    reformatted_code, stderrdata = p.communicate(
+        unformatted_code.encode('utf-8'))
+    self.assertIsNone(stderrdata)
+    self.assertEqual(reformatted_code.decode('utf-8'), unformatted_code)
+
 
 if __name__ == '__main__':
   unittest.main()