Repository: kivy/kivy

Issue:
TextInput doesn't wrap continuous text [$15]
Continuous text that is longer than one line, doesn't wrap to a second line in a multi-line TextInput.
## <bountysource-plugin>

There is a **[$15 open bounty](https://www.bountysource.com/issues/919619-textinput-doesn-t-wrap-continuous-text?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github)** on this issue. Add to the bounty at [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F42681&utm_medium=issues&utm_source=github).
</bountysource-plugin>



Discussion:
Is this still an issue with the new text wrapping stuff?

Yes, try typing a long line of text without spaces into the text input.

Any progress on this issue? Really needing this feature added to Kivy.


Resolving patch:
diff --git a/kivy/uix/textinput.py b/kivy/uix/textinput.py
--- a/kivy/uix/textinput.py
+++ b/kivy/uix/textinput.py
@@ -183,7 +183,9 @@ def insert_text(self, substring, from_undo=False):
 Cache_register('textinput.label', timeout=60.)
 Cache_register('textinput.width', timeout=60.)
 
-FL_IS_NEWLINE = 0x01
+FL_IS_LINEBREAK = 0x01
+FL_IS_WORDBREAK = 0x02
+FL_IS_NEWLINE = FL_IS_LINEBREAK | FL_IS_WORDBREAK
 
 # late binding
 Clipboard = None
@@ -558,9 +560,9 @@ def cursor_index(self, cursor=None):
                 if row >= len(l):
                     continue
                 index += len(l[row])
-                if lf[row] & FL_IS_NEWLINE:
+                if lf[row] & FL_IS_LINEBREAK:
                     index += 1
-            if lf[cr] & FL_IS_NEWLINE:
+            if lf[cr] & FL_IS_LINEBREAK:
                 index += 1
             return index
         except IndexError:
@@ -590,7 +592,7 @@ def get_cursor_from_index(self, index):
         i = 0
         for row in range(len(l)):
             ni = i + len(l[row])
-            if lf[row] & FL_IS_NEWLINE:
+            if lf[row] & FL_IS_LINEBREAK:
                 ni += 1
                 i += 1
             if ni >= index:
@@ -2142,6 +2144,17 @@ def _tokenize(self, text):
             oldindex = index + 1
         yield text[oldindex:]
 
+    def _split_word(self, text, width):
+        x = 0
+        split_pos = 0
+        for c in text:
+            cw = self._get_text_width(c, self.tab_width, self._label_cached)
+            if x + cw > width:
+                break
+            x += cw
+            split_pos += 1
+        return split_pos, x
+
     def _split_smart(self, text):
         # Do a "smart" split. If autowidth or autosize is set,
         # we are not doing smart split, just a split on line break.
@@ -2151,7 +2164,7 @@ def _split_smart(self, text):
         # depend of the options, split the text on line, or word
         if not self.multiline:
             lines = text.split(u'\n')
-            lines_flags = [0] + [FL_IS_NEWLINE] * (len(lines) - 1)
+            lines_flags = [0] + [FL_IS_LINEBREAK] * (len(lines) - 1)
             return lines, lines_flags
 
         # no autosize, do wordwrap.
@@ -2180,11 +2193,21 @@ def _split_smart(self, text):
                 line = []
                 x = 0
             if is_newline:
-                flags |= FL_IS_NEWLINE
+                flags |= FL_IS_LINEBREAK
+            elif w > width:
+                while w > width:
+                    split_pos, split_width = self._split_word(word, width)
+                    lines_append(word[:split_pos])
+                    lines_flags_append(FL_IS_WORDBREAK)
+                    flags = 0
+                    word = word[split_pos:]
+                    w -= split_width
+                x = w
+                line.append(word)
             else:
                 x += w
                 line.append(word)
-        if line or flags & FL_IS_NEWLINE:
+        if line or flags & FL_IS_LINEBREAK:
             lines_append(_join(line))
             lines_flags_append(flags)
 
@@ -2849,7 +2872,7 @@ def _get_text(self, encode=False):
         if len(lf) < len_l:
             lf.append(1)
 
-        text = u''.join([(u'\n' if (lf[i] & FL_IS_NEWLINE) else u'') + l[i]
+        text = u''.join([(u'\n' if (lf[i] & FL_IS_LINEBREAK) else u'') + l[i]
                         for i in range(len_l)])
 
         if encode and not isinstance(text, bytes):


Test patch: