continued refactor

This commit is contained in:
Michael Freno
2025-11-12 21:16:35 -05:00
parent 3df8718a62
commit 8206f96867
4 changed files with 304 additions and 473 deletions

View File

@@ -325,188 +325,8 @@ function TextEditor:_wrapLine(line, maxWidth)
return { { text = line, startIdx = 0, endIdx = utf8.len(line) } }
end
local font = self:_getFont()
if not font then
return { { text = line, startIdx = 0, endIdx = utf8.len(line) } }
end
local wrappedParts = {}
local currentLine = ""
local startIdx = 0
-- Helper function to extract a UTF-8 character by character index
local function getUtf8Char(str, charIndex)
local byteStart = utf8.offset(str, charIndex)
if not byteStart then
return ""
end
local byteEnd = utf8.offset(str, charIndex + 1)
if byteEnd then
return str:sub(byteStart, byteEnd - 1)
else
return str:sub(byteStart)
end
end
if self.textWrap == "word" then
-- Tokenize into words and whitespace, preserving exact spacing
local tokens = {}
local pos = 1
local lineLen = utf8.len(line)
while pos <= lineLen do
local char = getUtf8Char(line, pos)
if char:match("%s") then
-- Collect whitespace sequence
local wsStart = pos
while pos <= lineLen and getUtf8Char(line, pos):match("%s") do
pos = pos + 1
end
table.insert(tokens, {
type = "space",
text = line:sub(utf8.offset(line, wsStart), utf8.offset(line, pos) and utf8.offset(line, pos) - 1 or #line),
startPos = wsStart - 1,
length = pos - wsStart,
})
else
-- Collect word
local wordStart = pos
while pos <= lineLen and not getUtf8Char(line, pos):match("%s") do
pos = pos + 1
end
table.insert(tokens, {
type = "word",
text = line:sub(utf8.offset(line, wordStart), utf8.offset(line, pos) and utf8.offset(line, pos) - 1 or #line),
startPos = wordStart - 1,
length = pos - wordStart,
})
end
end
-- Process tokens and wrap
local charPos = 0
for i, token in ipairs(tokens) do
if token.type == "word" then
local testLine = currentLine .. token.text
local width = font:getWidth(testLine)
if width > maxWidth and currentLine ~= "" then
-- Current line is full, wrap before this word
local currentLineLen = utf8.len(currentLine)
table.insert(wrappedParts, {
text = currentLine,
startIdx = startIdx,
endIdx = startIdx + currentLineLen,
})
startIdx = charPos
currentLine = token.text
charPos = charPos + token.length
-- Check if the word itself is too long
if font:getWidth(token.text) > maxWidth then
local wordLen = utf8.len(token.text)
local charLine = ""
local charStartIdx = startIdx
for j = 1, wordLen do
local char = getUtf8Char(token.text, j)
local testCharLine = charLine .. char
local charWidth = font:getWidth(testCharLine)
if charWidth > maxWidth and charLine ~= "" then
table.insert(wrappedParts, {
text = charLine,
startIdx = charStartIdx,
endIdx = charStartIdx + utf8.len(charLine),
})
charStartIdx = charStartIdx + utf8.len(charLine)
charLine = char
else
charLine = testCharLine
end
end
currentLine = charLine
startIdx = charStartIdx
end
elseif width > maxWidth and currentLine == "" then
-- Word is too long to fit on a line by itself
local wordLen = utf8.len(token.text)
local charLine = ""
local charStartIdx = startIdx
for j = 1, wordLen do
local char = getUtf8Char(token.text, j)
local testCharLine = charLine .. char
local charWidth = font:getWidth(testCharLine)
if charWidth > maxWidth and charLine ~= "" then
table.insert(wrappedParts, {
text = charLine,
startIdx = charStartIdx,
endIdx = charStartIdx + utf8.len(charLine),
})
charStartIdx = charStartIdx + utf8.len(charLine)
charLine = char
else
charLine = testCharLine
end
end
currentLine = charLine
startIdx = charStartIdx
charPos = charPos + token.length
else
currentLine = testLine
charPos = charPos + token.length
end
else
-- It's whitespace - add to current line
currentLine = currentLine .. token.text
charPos = charPos + token.length
end
end
else
-- Character wrapping
local lineLength = utf8.len(line)
for i = 1, lineLength do
local char = getUtf8Char(line, i)
local testLine = currentLine .. char
local width = font:getWidth(testLine)
if width > maxWidth and currentLine ~= "" then
table.insert(wrappedParts, {
text = currentLine,
startIdx = startIdx,
endIdx = startIdx + utf8.len(currentLine),
})
currentLine = char
startIdx = i - 1
else
currentLine = testLine
end
end
end
-- Add remaining text
if currentLine ~= "" then
table.insert(wrappedParts, {
text = currentLine,
startIdx = startIdx,
endIdx = startIdx + utf8.len(currentLine),
})
end
-- Ensure at least one part
if #wrappedParts == 0 then
table.insert(wrappedParts, {
text = "",
startIdx = 0,
endIdx = 0,
})
end
return wrappedParts
-- Delegate to Renderer
return self._element._renderer:wrapLine(self._element, line, maxWidth)
end
-- ====================
@@ -1712,19 +1532,8 @@ function TextEditor:_getFont()
return nil
end
-- Resolve font path
local fontPath = nil
if self._element.fontFamily then
local Theme = req("Theme")
local themeToUse = self._element.theme and Theme.get(self._element.theme) or Theme.getActive()
if themeToUse and themeToUse.fonts and themeToUse.fonts[self._element.fontFamily] then
fontPath = themeToUse.fonts[self._element.fontFamily]
else
fontPath = self._element.fontFamily
end
end
return FONT_CACHE.getFont(self._element.textSize, fontPath)
-- Delegate to Renderer
return self._element._renderer:getFont(self._element)
end
---Save state to StateManager (for immediate mode)