diff --git a/Python-2.7.13/pyconfig.h b/Python-2.7.13/pyconfig.h index ce867a6304..693c93b63e 100644 --- a/Python-2.7.13/pyconfig.h +++ b/Python-2.7.13/pyconfig.h @@ -259,9 +259,6 @@ /* Define to 1 if you have the `ftello' function. */ #define HAVE_FTELLO 1 -/* Define to 1 if you have the `ftime' function. */ -#define HAVE_FTIME 1 - /* Define to 1 if you have the `ftruncate' function. */ #define HAVE_FTRUNCATE 1 diff --git a/build/cpython_defs.py b/build/cpython_defs.py index e5d4d17c38..9e6fa3a23f 100755 --- a/build/cpython_defs.py +++ b/build/cpython_defs.py @@ -305,8 +305,9 @@ def __call__(self, rel_path, def_name, method_name): # Auto-filtering gave false-positives here. # We don't need top-level next(). The method should be good enough. + # iter is a field name if (basename == 'bltinmodule.c' and - method_name in ('compile', 'format', 'next', 'vars')): + method_name in ('compile', 'format', 'next', 'vars', 'iter')): return False if basename == 'bltinmodule.c': # Get "bootstrapping error" without this. diff --git a/build/oil-defs/native/libc.c/methods.def b/build/oil-defs/native/libc.c/methods.def index 456652273a..e9fb7b94fb 100644 --- a/build/oil-defs/native/libc.c/methods.def +++ b/build/oil-defs/native/libc.c/methods.def @@ -9,5 +9,6 @@ static PyMethodDef methods[] = { {"print_time", func_print_time, METH_VARARGS}, {"gethostname", socket_gethostname, METH_NOARGS}, {"get_terminal_width", func_get_terminal_width, METH_NOARGS}, + {"wcswidth", func_wcswidth, METH_VARARGS}, {0}, }; diff --git a/core/comp_ui.py b/core/comp_ui.py index 21d0ae2c7e..d26d2bba62 100644 --- a/core/comp_ui.py +++ b/core/comp_ui.py @@ -32,7 +32,8 @@ def _PromptLen(prompt_str): """Ignore all characters between \x01 and \x02 and handle unicode characters. In particular, the display width of a string may be different from either the - number of bytes or the number of unicode characters.""" + number of bytes or the number of unicode characters. + Additionally, if there are multiple lines in the prompt, only give the length of the last line.""" escaped = False display_str = "" for c in prompt_str: @@ -42,11 +43,15 @@ def _PromptLen(prompt_str): escaped = False elif not escaped: display_str += c + last_line = display_str.split('\n')[-1] try: - return libc.wcswidth(display_str) + width = libc.wcswidth(last_line) # en_US.UTF-8 locale missing, just return the number of bytes except (SystemError, UnicodeError): return len(display_str) + if width == -1: + return len(display_str) + return width class PromptState(object): diff --git a/core/comp_ui_test.py b/core/comp_ui_test.py index e8b1484300..7650f7ce6c 100755 --- a/core/comp_ui_test.py +++ b/core/comp_ui_test.py @@ -165,6 +165,14 @@ def testValidEscapes(self): comp_ui._PromptLen("\x01\x02 hi \x01hi\x02 \x01\x02 hello"), len(" hi hello")) + def testNewline(self): + self.assertEqual(comp_ui._PromptLen("\n"), 0) + self.assertEqual(comp_ui._PromptLen("abc\ndef"), 3) + self.assertEqual(comp_ui._PromptLen(""), 0) + + def testControlCharacters(self): + self.assertEqual(comp_ui._PromptLen("\xef"), 1) + self.assertEqual(comp_ui._PromptLen("\x03\x05"), 2) if __name__ == '__main__': unittest.main() diff --git a/core/property_tests.py b/core/property_tests.py new file mode 100755 index 0000000000..0e29e21fd1 --- /dev/null +++ b/core/property_tests.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python2 + +import unittest + +from hypothesis import given +from hypothesis.strategies import text + +from comp_ui import _PromptLen + +class PromptTest(unittest.TestCase): + @given(text()) + def testNeverPanics(self, s): + self.assertIs(_PromptLen(s) >= 0, True) + +if __name__ == '__main__': + unittest.main() diff --git a/native/libc_test.py b/native/libc_test.py index 8d1e860a29..2ecb7f5ac0 100755 --- a/native/libc_test.py +++ b/native/libc_test.py @@ -193,6 +193,7 @@ def testGetTerminalWidth(self): def testWcsWidth(self): self.assertEqual(1, libc.wcswidth("▶️")) self.assertEqual(28, libc.wcswidth("(osh) ~/.../unchanged/oil ▶️ ")) + self.assertEqual(2, libc.wcswidth("→ ")) self.assertRaises(UnicodeError, libc.wcswidth, "\xfe") if __name__ == '__main__': diff --git a/osh/word.py b/osh/word.py index e4cf1d7afe..291cb9228b 100644 --- a/osh/word.py +++ b/osh/word.py @@ -155,7 +155,7 @@ def LeftMostSpanForPart(part): return part.spids[0] elif isinstance(part, word_part__TildeSubPart): - return const.NO_INTEGER + return part.token.span_id elif isinstance(part, word_part__ArithSubPart): # begin, end diff --git a/test/lint.sh b/test/lint.sh index 7e4c370d32..fd786442be 100755 --- a/test/lint.sh +++ b/test/lint.sh @@ -90,8 +90,7 @@ bin-flake8() { if test -f "$ubuntu_flake8"; then $ubuntu_flake8 "$@" else - # Assume it's in $PATH, like on Travis. - flake8 "$@" + python2 -m flake8 "$@" fi } diff --git a/vendor/typing.py b/vendor/typing.py index b0fdb1c2d7..a9a700bf7d 100644 --- a/vendor/typing.py +++ b/vendor/typing.py @@ -10,6 +10,9 @@ # if TYPE_CHECKING: # NullFunc = Callable[[int, int], int] +TypingMeta = None +TypeVar = None +_ForwardRef = None List = None Tuple = None Optional = None