local error = error
local find = string.find
local gmatch = string.gmatch
local match = string.match
local sub = string.sub
--[==[
Iterates over the lines in a string, treating {"\n"}, {"\r"} and {"\r\n"} as new lines.
The optional {skip} parameter determines whether certain lines are skipped:
* {NONE}: none (default).
* {EMPTY}: empty lines: lines with a length of 0, consisting of no characters.
* {BLANK}: blank lines: empty lines and lines which only consist of whitespace characters.]==]
return function(str, skip)
-- Use gmatch() for EMPTY and BLANK, for speed.
if skip == "EMPTY" then
return gmatch(str, "+")
elseif skip == "BLANK" then
return gmatch(str, "-%S*")
elseif not (skip == nil or skip == "NONE") then
error("bad argument #2 to 'string/gline' (expected NONE, EMPTY or BLANK)", 2)
end
local start, linechar, flag = 1
if not find(str, "\n", nil, true) then
if not find(str, "\r", nil, true) then
-- No newlines: return `str` on the first iteration then end.
return function()
if flag then
return
end
flag = true
return str
end
end
linechar = "\r"
elseif find(str, "\r", nil, true) then
-- Newline could be "\n", "\r" or "\r\n" (but not "\n\r").
return function()
if not flag then
local line, nl, pos = match(str, "^(*)(\n?)()", start)
if not line then
flag = true
return sub(str, start)
end
-- If `nl` is "\r\n" it should be treated as a single newline,
-- but if it's "\n\n" it needs to be treated as two separate
-- newlines, so set `flag` to 2 to avoid an unnecessary match()
-- call on the next iteration.
if nl == "\n\n" then
flag = 2
end
start = pos
return line
elseif flag == 2 then
flag = nil
return ""
end
end
else
linechar = "\n"
end
-- Newline is either "\n" or "\r", depending on which has been found.
return function()
if flag then
return
end
local pos = find(str, linechar, start, true)
if not pos then
flag = true
return sub(str, start)
end
local line = sub(str, start, pos - 1)
start = pos + 1
return line
end
end