Fix core.wrap_text and make its behaviour consistent with the docs
authorsfan5 <sfan5@live.de>
Mon, 11 Sep 2017 14:25:20 +0000 (16:25 +0200)
committersfan5 <sfan5@live.de>
Tue, 12 Sep 2017 17:33:00 +0000 (19:33 +0200)
Code based on initial implementation by @dsohler.

builtin/common/misc_helpers.lua
builtin/mainmenu/common.lua
builtin/mainmenu/tab_mods.lua
doc/lua_api.txt

index 5fc589b72f3164b0429d9d2563a4be1fcca5ba1b..87561726e7e1776bcef0e38074d4d4e80675d8e8 100644 (file)
@@ -308,59 +308,25 @@ function core.formspec_escape(text)
 end
 
 
-function core.wrap_text(text, charlimit)
-       local retval = {}
-
-       local current_idx = 1
-
-       local start,stop = string_find(text, " ", current_idx)
-       local nl_start,nl_stop = string_find(text, "\n", current_idx)
-       local gotnewline = false
-       if nl_start ~= nil and (start == nil or nl_start < start) then
-               start = nl_start
-               stop = nl_stop
-               gotnewline = true
-       end
-       local last_line = ""
-       while start ~= nil do
-               if string.len(last_line) + (stop-start) > charlimit then
-                       retval[#retval + 1] = last_line
-                       last_line = ""
+function core.wrap_text(text, max_length, as_table)
+       local result = {}
+       local line = {}
+       if #text <= max_length then
+               return as_table and {text} or text
+       end
+
+       for word in text:gmatch('%S+') do
+               local cur_length = #table.concat(line, ' ')
+               if cur_length > 0 and cur_length + #word + 1 >= max_length then
+                       -- word wouldn't fit on current line, move to next line
+                       table.insert(result, table.concat(line, ' '))
+                       line = {}
                end
-
-               if last_line ~= "" then
-                       last_line = last_line .. " "
-               end
-
-               last_line = last_line .. string_sub(text, current_idx, stop - 1)
-
-               if gotnewline then
-                       retval[#retval + 1] = last_line
-                       last_line = ""
-                       gotnewline = false
-               end
-               current_idx = stop+1
-
-               start,stop = string_find(text, " ", current_idx)
-               nl_start,nl_stop = string_find(text, "\n", current_idx)
-
-               if nl_start ~= nil and (start == nil or nl_start < start) then
-                       start = nl_start
-                       stop = nl_stop
-                       gotnewline = true
-               end
-       end
-
-       --add last part of text
-       if string.len(last_line) + (string.len(text) - current_idx) > charlimit then
-                       retval[#retval + 1] = last_line
-                       retval[#retval + 1] = string_sub(text, current_idx)
-       else
-               last_line = last_line .. " " .. string_sub(text, current_idx)
-               retval[#retval + 1] = last_line
+               table.insert(line, word)
        end
 
-       return retval
+       table.insert(result, table.concat(line, ' '))
+       return as_table and result or table.concat(result, '\n')
 end
 
 --------------------------------------------------------------------------------
index fa7ae583b5826016ef670680356b965a471e545e..7eb941775b9b67fc86fe4aeb365ba78402a2f9b1 100644 (file)
@@ -250,7 +250,7 @@ end
 
 --------------------------------------------------------------------------------
 function text2textlist(xpos, ypos, width, height, tl_name, textlen, text, transparency)
-       local textlines = core.wrap_text(text, textlen)
+       local textlines = core.wrap_text(text, textlen, true)
        local retval = "textlist[" .. xpos .. "," .. ypos .. ";" .. width ..
                        "," .. height .. ";" .. tl_name .. ";"
 
index d829c2cce7576d6b3e36ed1fe6109364c9be7482..e74fb442c7674c59fa312cb0780fa08af5f5f10e 100644 (file)
@@ -66,7 +66,7 @@ local function get_formspec(tabview, name, tabdata)
                if error == nil then
                        local descriptiontext = descriptionfile:read("*all")
 
-                       descriptionlines = core.wrap_text(descriptiontext, 42)
+                       descriptionlines = core.wrap_text(descriptiontext, 42, true)
                        descriptionfile:close()
                else
                        descriptionlines = {}
index 9a5754368e5c4706a951ec2bb566ee6ceb243dbe..3c2278c8dc853f6a368a52b724210bd3f63a3d91 100644 (file)
@@ -2158,9 +2158,11 @@ Helper functions
     * e.g. `string:split("a,b", ",") == {"a","b"}`
 * `string:trim()`
     * e.g. `string.trim("\n \t\tfoo bar\t ") == "foo bar"`
-* `minetest.wrap_text(str, limit)`: returns a string
-    * Adds new lines to the string to keep it within the specified character limit
+* `minetest.wrap_text(str, limit, [as_table])`: returns a string or table
+    * Adds newlines to the string to keep it within the specified character limit
+      Note that returned lines may be longer than the limit since it only splits at word borders.
     * limit: Maximal amount of characters in one line
+    * as_table: optional, if true return table of lines instead of string
 * `minetest.pos_to_string({x=X,y=Y,z=Z}, decimal_places))`: returns string `"(X,Y,Z)"`
     * Convert position to a printable string
       Optional: 'decimal_places' will round the x, y and z of the pos to the given decimal place.