[Tex/LaTex] Search & Replace Script for TeXworks

luascriptstexworks

Does anyone have an example for a search & replace lua script that I can use with TeXworks. I have a rather large document here (about 3'000 pages DIN A5) which I need to update continously. To change $to \$ and various other replacements I would like to run a 'replace-all' script which makes all the replacements in a single run.

This could be quite useful when one has to take text from e.g. MS Word or the WWW.

Best Answer

Your question is very interesting, I promise to upvote it as soon as possible. As usual, I'm out of votes.

I'll try to write a humble answer. I'm really sorry if the solution might cause any trouble due to any bug or annoyance, I'm a Lua newbie. :)

First things first: we need to enable the scripting language plugin in TeXworks. We can do it by simply going to the Preferences, in the Scripts tab:

Preferences

We just need to mark the checkbox. :)

Now, let's see where to put our script. Go to Scripts, Scripting TeXworks, Show Scripts Folder:

Scripts menu

The operating system file manager will appear with the folder we want. :)

Scripts folder

In my Mac, it's under ~/Library/TeXworks/scripts. Now, create a new file named replaceList.lua and add the following content, as it is:

--[[TeXworksScript
Title: Replace list
Description: A replacement script
Author: Paulo Cereda
Version: 1.0
Date: 2012-11-28
Script-Type: standalone
Context: TeXDocument
]]

-- implements the 'strip' function in order to extract
-- elements from a string according to a specific
-- separator. The output is a table containing each
-- element from the input string.
-- Thanks to the http://lua-users.org/wiki/SplitJoin wiki.
string.split = function(str, pattern)
    pattern = pattern or "[^%s]+"    
    if pattern:len() == 0 then    
        pattern = "[^%s]+"    
    end    
    local parts = {__index = table.insert}   
    setmetatable(parts, parts)    
    str:gsub(pattern, parts)    
    setmetatable(parts, nil)   
    parts.__index = nil   
    return parts
end   

-- gets a string containing a list of patterns. This is
-- the first dialog window that appears in the script
-- execution.
local listOfPatterns = TW.getText(nil, "List of patterns to replace  - 1/2", "Please, add a list of patterns to replace, separated by comma.")

-- gets a string containing a list of words to replace the
-- patterns obtainted in the previous step. This is the
-- second dialog window that appears in the script
-- execution
local listOfReplacements = TW.getText(nil, "List of patterns to replace  - 2/2", "Please, add a list of replacements, separated by comma.")

-- checks if both inputs are valid
if (listOfPatterns ~= nil) and (listOfReplacements) then

    -- split the patterns into elements of a table. In our
    -- case, the separator is a comma.
    local patternsToLook = string.split(listOfPatterns, "[^,%s]+")

    -- split the values into elements of a table. In our case,
    -- the separator is a comma.
    local valuesToReplace = string.split(listOfReplacements, "[^,%s]+")

    -- the number of elements of both tables must be equal
    if (#patternsToLook == #valuesToReplace) then

        -- iterate through the patterns table
        for index, currentValue in ipairs(patternsToLook) do

            -- select all the text from the current
            -- document
            TW.target.selectAll();

            -- get all the selected text
            local text = TW.target.selection

            -- checks if there's actually a text
            if (text ~= nil) then

                -- replace all occurrences of the current
                -- pattern by its corresponding value
                local toReplace, _ = string.gsub(text, currentValue, valuesToReplace[index])

                -- insert modified text into the
                -- document
                TW.target.insertText(toReplace)
            end
        end 
    end
end

My sincere apologies to Patrick, Taco and other Lua masters. :)

Now, we have a new file in our folder, replaceList.lua:

New file

Now, back to TeXworks, we need to reload our list of scripts. It's easy, we need to go to Scripts, Scripting TeXworks, Reload Scripts List:

Reload scripts

Done. :) Let's create a test file:

My document

Time to run our script. Simply go to Scripts and select Replace list:

Running the script

Now, the magic of TeXworks scripting API will appear. First, we will define a list of patterns to look for:

List of patterns

Regex supported, I guess.

I'm telling our script to look for three words, separated by commas. After clicking OK, a new window will appear, with a list of replacement words:

Replacements

Of course, both lists have to have the very same size. :) After we click OK, our new text is presented:

New document

There we go! :) I hope my humble answer helps. :)