optimized wrapWords; fixes #14579 (#14606) [backport:1.2]

This commit is contained in:
Andreas Rumpf 2020-06-08 14:34:26 +02:00 • committed by GitHub
commit c308c2e60b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -11,10 +11,10 @@
import strutils, unicode import strutils, unicode
proc olen(s: string): int = proc olen(s: string; start, lastExclusive: int): int =
var i = 0 var i = start
result = 0 result = 0
while i < s.len: while i < lastExclusive:
inc result inc result
let L = graphemeLen(s, i) let L = graphemeLen(s, i)
inc i, L inc i, L
@ -32,31 +32,46 @@ proc wrapWords*(s: string, maxLineWidth = 80,
result = newStringOfCap(s.len + s.len shr 6) result = newStringOfCap(s.len + s.len shr 6)
var spaceLeft = maxLineWidth var spaceLeft = maxLineWidth
var lastSep = "" var lastSep = ""
for word, isSep in tokenize(s, seps):
let wlen = olen(word)
if isSep:
lastSep = word
spaceLeft = spaceLeft - wlen
elif wlen > spaceLeft:
if splitLongWords and wlen > maxLineWidth:
var i = 0 var i = 0
while i < word.len: while true:
var j = i
let isSep = j < s.len and s[j] in seps
while j < s.len and (s[j] in seps) == isSep: inc(j)
if j <= i: break
#yield (substr(s, i, j-1), isSep)
if isSep:
lastSep.setLen 0
for k in i..<j:
if s[k] notin {'\L', '\C'}: lastSep.add s[k]
if lastSep.len == 0:
lastSep.add ' '
dec spaceLeft
else:
spaceLeft = spaceLeft - olen(lastSep, 0, lastSep.len)
else:
let wlen = olen(s, i, j)
if wlen > spaceLeft:
if splitLongWords and wlen > maxLineWidth:
var k = 0
while k < j - i:
if spaceLeft <= 0: if spaceLeft <= 0:
spaceLeft = maxLineWidth spaceLeft = maxLineWidth
result.add newLine result.add newLine
dec spaceLeft dec spaceLeft
let L = graphemeLen(word, i) let L = graphemeLen(s, k+i)
for j in 0 ..< L: result.add word[i+j] for m in 0 ..< L: result.add s[i+k+m]
inc i, L inc k, L
else: else:
spaceLeft = maxLineWidth - wlen spaceLeft = maxLineWidth - wlen
result.add(newLine) result.add(newLine)
result.add(word) for k in i..<j: result.add(s[k])
else: else:
spaceLeft = spaceLeft - wlen spaceLeft = spaceLeft - wlen
result.add(lastSep) result.add(lastSep)
result.add(word) for k in i..<j: result.add(s[k])
lastSep.setLen(0) #lastSep.setLen(0)
i = j
when isMainModule: when isMainModule:
@ -93,3 +108,11 @@ tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολ
ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε""" ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
doAssert wrapWords(longlongword) == longlongwordRes doAssert wrapWords(longlongword) == longlongwordRes
# bug #14579
const input60 = """
This is a long string. It is manually wrapped to 60
characters. I would not expect it to be changed by
wordwrap if wordwrap is set to wrap at 80 characters"""
const input60Res = """This is a long string. It is manually wrapped to 60 characters. I would not
expect it to be changed by wordwrap if wordwrap is set to wrap at 80 characters"""
doAssert wrapWords(input60) == input60Res