Convert Text From Source to Rich Text.fh_lua

--[[
@Title: Convert Text From Source to Rich Text
@Type: Standard
@Author: Jane Taubman
@Version: 1.0
@Keywords: Rich Text
@LastUpdated: 27 Nov 2020
@Description: Updates Text from source for the source currently selected,  
if you have multiple sources selected all will be prompted until the process is aborted or the list is completed.  
In the first prompt select the table text, no selection will treat the whole text as a table and the delimiter, then click OK.
The results for each source will be shown in a Rich Text prompt where you can adjust as needed before clicking OK.
N.B If you have comma separated texts, the plugin will use your place records to try and identify the places. If the place is not found you will
find you have additional columns
]]
fhInitialise(7)
fh = require('fhutils')
fh.setIupDefaults()
stringx.import()
local dlg
local options = fh.loadOptions({charWidth = 5.5 * 20, padding = 2,delimit = {"\t",",","|",";"},default='2'})

function main()
    local ptrList = fhGetCurrentRecordSel('SOUR')
    if not(ptrList[1]) or ptrList[1]:IsNull() then
        ptrList[1] = fhGetCurrentPropertyBoxRecord()
    end
    if not(ptrList[1]) or fhGetTag(ptrList[1]) ~= 'SOUR' then
        ptrList = fhPromptUserForRecordSel('SOUR')
        if #ptrList == 0 then return end
    end
    iMax = #ptrList
    for i,ptr in pairs(ptrList) do
        sErr = ''
        bCancel = true
        ptrText = fhGetItemPtr(ptr,'~.TEXT')
        if ptrText:IsNull() then
            sErr = 'No Text From Source Found.'
        end
        rText = fhGetValueAsRichText(ptrText)
        if rText:IsRich() then
            sErr = 'Text is already in Rich Text Format and can not be processed.'
        end
        if sErr == '' then
            sText = fhGetValueAsText(ptrText)
            sNew = promptDialog(sText)
            if sNew ~= sText then
                rt = fhNewRichText()
                rt:SetText(sNew, true)
                rtNew = fhPromptUserForRichText(rt)
                if rtNew then
                    fhSetValueAsRichText(ptrText,rtNew)
                    bCancel = false
                end
            end
        end
        if bCancel then
            if iMax == i then
                if sErr ~= '' then
                    fhMessageBox(sErr, "MB_OK")
                end
                return
            else
                local c= iMax - i
                local a = fhMessageBox(sErr.. "\nDo you wish to continue with the remaining "..c.." record(s)?", "MB_YESNO")
                if a ~="Yes" then return end
            end
        end
    end
    
end

function promptDialog(sText)
    -- Search for tab or pipe to set default
    listValue = options.default or '2'
    if sText:count("\t") > 0 then listValue = '1' end
    if sText:count("|") > 0 then listValue = '3' end
    local txtBox = iup.text{value=sText,multiline="YES",EXPAND="Yes",readonly="YES"}
    local bOk = false
    local btn = iup.button { title="OK";padding="20x4"}

    function btn.action()
        bOk = true
        return iup.CLOSE
    end
    local list = iup.list {"Tab","Comma ,","Pipe |","Other";dropdown="YES";value=listValue,
        killfocus_cb = function(self)
            local v = self.value
            -- v = v:replace('\t',"\t")
            options.default = v
            fh.saveOptions(options)
        end
    }
    local otherDelimit = iup.text{value = options.delimit[4] , mask='.', padding='1x1',size="10x10",
        killfocus_cb = function(self)
            options.delimit[4] = self.value
            fh.saveOptions(options)
        end
    }
    local vbox = iup.vbox {gap=20 , padding="10x10",
        iup.label {title="Please select text which will be a table"},
        txtBox,
        iup.hbox{gap=20,alignment="ACENTER",
            iup.label{title='Select Column Separator'}, list,
            iup.label{title='Other Separator'}, otherDelimit
        },
    btn }
    dlg = iup.dialog{vbox; title="Convert Text From Source to Rich Text"; size="QUARTERxQUARTER"}
    iup.SetAttribute(dlg, "NATIVEPARENT", fhGetContextInfo("CI_PARENT_HWND")); -- Set the parent window handle
    iup.SetHandle("main", dlg)
    iup.SetGlobal("PARENTDIALOG", "main");
    dlg:popup()
    if bOk then
        local s = txtBox.SELECTEDTEXT
        if s then
            sOld = s
        else
            sOld = sText
            s = sText
        end
        local n = tonumber(list.value)
        local sChr = options.delimit[n]
        if sChr == ',' then
            s = cvtComma(s)
            sChr = '|'
        end
        sTable = cvtText(s,sChr)
        sText = sText:replace(sOld,sTable)
    end
    dlg:destroy()
    return sText
end

function cvtComma(sOrg)
    -- Search for Place Name Strings and keep them while converting , to |
    local tNew = {}
    local tblPlaces = fhGetDataList('PLACES')
    for line in sOrg:lines() do
        local tMatch = {}
        for _,p in ipairs(tblPlaces) do
            if line:lfind(p) then
                table.insert(tMatch,p)
            end
        end
        -- Find Longest Match
        local p = ''
        local iLen = 0
        for _,v in pairs(tMatch) do
            if v:len() > iLen then
                p = v
                iLen = v:len()
            end
        end
        -- Replace
        pTemp = p:replace(',','~')
        line = line:replace(p,pTemp)
        line = line:replace(',','|')
        line = line:replace('~',',')
        table.insert(tNew,line)
    end
    return table.concat(tNew,"\n")
end

function cvtText(s,sChr)
    local sWidth = '2000'
    local tWidth = {}
    local rt = ''
    local line = s:splitlines()
    -- Find Max column count
    local hcol = 0
    for _,v in ipairs(line) do
        local col = v:split(sChr)
        if #col > hcol then
            hcol = #col
        end
        for i,txt in ipairs(col) do
            local txt = txt:strip()
            local w = (txt:len() + options.padding) * options.charWidth
            if not(tWidth[i]) or tWidth[i] < w then
                tWidth[i] = w
            end
        end
    end
    rt = "\n"
    for _,v in ipairs(line) do
        rt = rt.."\n"
        local col = v:split(sChr)
        for i,c in ipairs(col) do
            c= c:strip()
            if i > hcol and sChr == ',' then
                rt = rt..c..','
            else
                rt = rt..c..'|'
            end
        end
        rt:sub(1, #rt - 1)
        rt = rt..''
    end
    rt=rt.."\n"
    return rt
end
main();

Source:Convert-Text-From-Source-to-Rich-Text-1.fh_lua