<commit_before>-- © 2008 <NAME>.
-- WordGrinder is licensed under the MIT open source license. See the COPYING
-- file in this distribution for the full text.

local int = math.floor
local Write = wg.write
local SetNormal = wg.setnormal
local SetBold = wg.setbold
local SetUnderline = wg.setunderline
local SetReverse = wg.setreverse
local GetStringWidth = wg.getstringwidth

local redrawpending = true

-- Determine the user's home directory.

HOME = os.getenv("HOME") or os.getenv("USERPROFILE")

-- Which config file are we loading?

local configfile = HOME .. "/.wordgrinder.lua"

local oldcp, oldcw, oldco
function QueueRedraw()
	redrawpending = true
	if Document then
		if (oldcp ~= Document.cp) or (oldcw ~= Document.cw) or
				(oldco ~= Document.co) then
			oldcp = Document.cp
			oldcw = Document.cw
			oldco = Document.co
			FireAsyncEvent(Event.Moved)
		end

		if not Document.wrapwidth then
			ResizeScreen()
		end
	end
end

function ResetDocumentSet()
	DocumentSet = CreateDocumentSet()
	DocumentSet.menu = CreateMenu()
	DocumentSet:addDocument(CreateDocument(), "main")
	DocumentSet:setCurrent("main")
	RebuildParagraphStylesMenu(DocumentSet.styles)
	RebuildDocumentsMenu(DocumentSet.documents)
	DocumentSet:purge()
	DocumentSet:clean()
	
	FireEvent(Event.DocumentCreated)
	FireEvent(Event.RegisterAddons)
end

do
	local function cb(event, token)
		oldcp = nil
		oldcw = nil
		oldco = nil
	end

	AddEventListener(Event.DocumentLoaded, cb)
	AddEventListener(Event.DocumentCreated, cb)
end
	
-- This function contains the word processor proper, including the main event
-- loop.

function WordProcessor(filename)
	LoadGlobalSettings()

	do
		local f, e = loadfile(configfile)
		if e and not e:find("No such file or directory") then
			CLIError("config file compilation error: "..e)
		end

		if not e then
			xpcall(f, CLIError)
		end
	end

	wg.initscreen()
	ResizeScreen()
	RedrawScreen()
	FireEvent(Event.DocumentLoaded)
	
	if filename then
		Cmd.LoadDocumentSet(filename)
	end
	
	--ModalMessage("Welcome!", "Welcome to WordGrinder! While editing, you may press ESC for the menu, or ESC, F, X to exit (or ALT+F, X if your terminal supports it).")
	
	local masterkeymap = {
		["KEY_RESIZE"] = function() -- resize
			ResizeScreen()
			RedrawScreen()
		end,
		
		["KEY_REDRAW"] = RedrawScreen,
		
		[" "] = Cmd.SplitCurrentWord,
		["KEY_RETURN"] = Cmd.SplitCurrentParagraph,
		["KEY_ESCAPE"] = Cmd.ActivateMenu,
	}	
		
	local function eventloop()
		local nl = string.char(13)
		while true do
			if DocumentSet.justchanged then
				FireEvent(Event.Changed)
				DocumentSet.justchanged = false
			end
			
			FlushAsyncEvents()
			FireEvent(Event.WaitingForUser)
			local c = "KEY_TIMEOUT"
			while (c == "KEY_TIMEOUT") do
				if redrawpending then
					RedrawScreen()
					redrawpending = false
				end
			
				c = wg.getchar(DocumentSet.idletime)
				if (c == "KEY_TIMEOUT") then
					FireEvent(Event.Idle)
				end
			end
			
			ResetNonmodalMessages()
			
			-- Anything in masterkeymap overrides everything else.
			local f = masterkeymap[c]
			if f then
				f()
			else
				-- It's not in masterkeymap. If it's printable, insert it; if it's
				-- not, look it up in the menu hierarchy.
				
				if not c:match("^KEY_") then
					Cmd.TypeWhileSelected()
					Cmd.InsertStringIntoWord(c)
				else
					f = DocumentSet.menu:lookupAccelerator(c)
					if f then
						if IsMenu(f) then
							Cmd.ActivateMenu(f)
						else
							f()
						end
					else
						NonmodalMessage(c:gsub("^KEY_", "").." is not bound --- try ESCAPE for a menu")
					end
				end
			end
		end
	end
	
	while true do
		local f, e = xpcall(eventloop, Traceback)
		if not f then
			ModalMessage("Internal error!",
				"Something went wrong inside WordGrinder! I'll try and "..
				"continue but you should save your work immediately (under a "..
				"different filename), exit, and send the following technical "..
				"information to the author:\n\n" .. e)
		end
	end
end

-- Program entry point. Parses command line arguments and executes.

function Main(...)
	-- Set up the initial document so that the command line options have
	-- access.
	
	ResetDocumentSet()

	local filename = nil
	do
		local stdout = io.stdout
		local stderr = io.stderr
		
		local function do_help(opt)
			stdout:write("WordGrinder version ", VERSION, " © 2007-2008 <NAME>\n")
			if DEBUG then
				stdout:write("(This version has been compiled with debugging enabled.)\n")
			end
			
			stdout:write([[
Syntax: wordgrinder [<options...>] [<filename>]
Options:
   -h    --help                Displays this message.
         --lua file.lua        Loads and executes file.lua and then exits
		                       (or file.lua can be some Lua statements)
   -c    --convert src dest    Converts from one file format to another
         --config file.lua     Sets the name of the user config file

Only one filename may be specified, which is the name of a WordGrinder
file to load on startup. If not given, you get a blank document instead.

To convert documents, use --convert. The file type is autodetected from the
extension. To specify a document name, use :name as a suffix. e.g.:

    wordgrinder --convert filename.wg:"Chapter 1" chapter1.odt

The user config file is a Lua file which is loaded and executed before
the program starts up (but after any --lua files). It defaults to:

    ]] .. configfile .. [[


]])
			if DEBUG then
				-- List debugging options here.
			end
			
			os.exit(0)
		end
		
		local function do_lua(opt1, opt2)
			if not opt1 then
				CLIError("--lua must have an argument")
			end

			local f, e = loadfile(opt1)
			if e and e:find("No such file or directory") then
				f, e = loadstring(opt1)
			end
			if e then
				CLIError("user script compilation error: "..e)
			end

			f(opt2)
			os.exit(0)
		end
		
		local function do_convert(opt1, opt2)
			if not opt1 or not opt2 then
				CLIError("--convert must have two arguments")
			end
			
			CliConvert(opt1, opt2)
		end
		
		local function do_config(opt1, opt2)
			if not opt1 then
				CLIError("--config must have an argument")
			end

			configfile = opt1
			return 1
		end

		local function needarg(opt)
			if not opt then
				CLIError("missing option parameter")
			end
		end
		
		local argmap = {
			["h"]           = do_help,
			["help"]        = do_help,
			["lua"]         = do_lua,
			["c"]           = do_convert,
			["convert"]     = do_convert,
			["config"]      = do_config,
		}
		
		if DEBUG then
			-- argmap["p"] = do_profile
			-- argmap["profile"] = do_profile
		end
		 
		-- Called on an unrecognised option.
		
		local function unrecognisedarg(arg)
			CLIError("unrecognised option '", arg, "' --- try --help for help")
		end
		
		-- Do the actual argument parsing.
		
		local arg = {...}
		local i = 2
		while (i <= #arg) do
			local o = arg[i]
			local op
			
			if (o:byte(1) == 45) then
				-- This is an option.
				if (o:byte(2) == 45) then
					-- ...with a -- prefix.
					o = o:sub(3)
					local fn = argmap[o]
					if not fn then
						unrecognisedarg("--"..o)
					end
					i = i + fn(arg[i+1], arg[i+2])
				else
					-- ...without a -- prefix.
					local od = o:sub(2, 2)
					local fn = argmap[od]
					if not fn then
						unrecognisedarg("-"..od)
					end
					op = o:sub(3)
					if (op == "") then
						i = i + fn(arg[i+1], arg[i+2])
					else
						fn(op)
					end
				end
			else
				if filename then
					CLIError("you may only specify one filename")
				end
				filename = o
			end	

			i = i + 1
		end
	end
	
	if filename and
			not filename:find("^/") and
			not filename:find("^[a-zA-Z]:[/\\]") then
		filename = lfs.currentdir() .. "/" .. filename
	end
	
	WordProcessor(filename)
end
<commit_msg>Refactor grouped actions so that we can use them in the keymap override table and global keymap.<commit_after>-- © 2008 <NAME>.
-- WordGrinder is licensed under the MIT open source license. See the COPYING
-- file in this distribution for the full text.

local int = math.floor
local Write = wg.write
local SetNormal = wg.setnormal
local SetBold = wg.setbold
local SetUnderline = wg.setunderline
local SetReverse = wg.setreverse
local GetStringWidth = wg.getstringwidth

local redrawpending = true

-- Determine the user's home directory.

HOME = os.getenv("HOME") or os.getenv("USERPROFILE")

-- Which config file are we loading?

local configfile = HOME .. "/.wordgrinder.lua"

local oldcp, oldcw, oldco
function QueueRedraw()
	redrawpending = true
	if Document then
		if (oldcp ~= Document.cp) or (oldcw ~= Document.cw) or
				(oldco ~= Document.co) then
			oldcp = Document.cp
			oldcw = Document.cw
			oldco = Document.co
			FireAsyncEvent(Event.Moved)
		end

		if not Document.wrapwidth then
			ResizeScreen()
		end
	end
end

function ResetDocumentSet()
	DocumentSet = CreateDocumentSet()
	DocumentSet.menu = CreateMenu()
	DocumentSet:addDocument(CreateDocument(), "main")
	DocumentSet:setCurrent("main")
	RebuildParagraphStylesMenu(DocumentSet.styles)
	RebuildDocumentsMenu(DocumentSet.documents)
	DocumentSet:purge()
	DocumentSet:clean()
	
	FireEvent(Event.DocumentCreated)
	FireEvent(Event.RegisterAddons)
end

do
	local function cb(event, token)
		oldcp = nil
		oldcw = nil
		oldco = nil
	end

	AddEventListener(Event.DocumentLoaded, cb)
	AddEventListener(Event.DocumentCreated, cb)
end
	
-- This function contains the word processor proper, including the main event
-- loop.

function WordProcessor(filename)
	LoadGlobalSettings()

	do
		local f, e = loadfile(configfile)
		if e and not e:find("No such file or directory") then
			CLIError("config file compilation error: "..e)
		end

		if not e then
			xpcall(f, CLIError)
		end
	end

	wg.initscreen()
	ResizeScreen()
	RedrawScreen()
	FireEvent(Event.DocumentLoaded)
	
	if filename then
		Cmd.LoadDocumentSet(filename)
	end
	
	--ModalMessage("Welcome!", "Welcome to WordGrinder! While editing, you may press ESC for the menu, or ESC, F, X to exit (or ALT+F, X if your terminal supports it).")
	
	local masterkeymap = {
		["KEY_RESIZE"] = function() -- resize
			ResizeScreen()
			RedrawScreen()
		end,
		
		["KEY_REDRAW"] = RedrawScreen,
		
		[" "] = { Cmd.TypeWhileSelected, Cmd.SplitCurrentWord },
		["KEY_RETURN"] = { Cmd.TypeWhileSelected, Cmd.SplitCurrentParagraph },
		["KEY_ESCAPE"] = Cmd.ActivateMenu,
	}	
		
	local function runaction(ff)
		if (type(ff) == "function") then
			return ff()
		elseif IsMenu(f) then
			Cmd.ActivateMenu(f)
		else
			local r = true
			for _, f in ipairs(ff) do
				r = r and f()
			end
			return r
		end
	end

	local function eventloop()
		local nl = string.char(13)
		while true do
			if DocumentSet.justchanged then
				FireEvent(Event.Changed)
				DocumentSet.justchanged = false
			end
			
			FlushAsyncEvents()
			FireEvent(Event.WaitingForUser)
			local c = "KEY_TIMEOUT"
			while (c == "KEY_TIMEOUT") do
				if redrawpending then
					RedrawScreen()
					redrawpending = false
				end
			
				c = wg.getchar(DocumentSet.idletime)
				if (c == "KEY_TIMEOUT") then
					FireEvent(Event.Idle)
				end
			end
			
			ResetNonmodalMessages()
			
			-- Anything in masterkeymap overrides everything else.
			local f = masterkeymap[c]
			if f then
				runaction(f)
			else
				-- It's not in masterkeymap. If it's printable, insert it; if it's
				-- not, look it up in the menu hierarchy.
				
				if not c:match("^KEY_") then
					Cmd.TypeWhileSelected()
					Cmd.InsertStringIntoWord(c)
				else
					f = DocumentSet.menu:lookupAccelerator(c)
					if f then
						runaction(f)
					else
						NonmodalMessage(c:gsub("^KEY_", "").." is not bound --- try ESCAPE for a menu")
					end
				end
			end
		end
	end
	
	while true do
		local f, e = xpcall(eventloop, Traceback)
		if not f then
			ModalMessage("Internal error!",
				"Something went wrong inside WordGrinder! I'll try and "..
				"continue but you should save your work immediately (under a "..
				"different filename), exit, and send the following technical "..
				"information to the author:\n\n" .. e)
		end
	end
end

-- Program entry point. Parses command line arguments and executes.

function Main(...)
	-- Set up the initial document so that the command line options have
	-- access.
	
	ResetDocumentSet()

	local filename = nil
	do
		local stdout = io.stdout
		local stderr = io.stderr
		
		local function do_help(opt)
			stdout:write("WordGrinder version ", VERSION, " © 2007-2008 <NAME>\n")
			if DEBUG then
				stdout:write("(This version has been compiled with debugging enabled.)\n")
			end
			
			stdout:write([[
Syntax: wordgrinder [<options...>] [<filename>]
Options:
   -h    --help                Displays this message.
         --lua file.lua        Loads and executes file.lua and then exits
		                       (or file.lua can be some Lua statements)
   -c    --convert src dest    Converts from one file format to another
         --config file.lua     Sets the name of the user config file

Only one filename may be specified, which is the name of a WordGrinder
file to load on startup. If not given, you get a blank document instead.

To convert documents, use --convert. The file type is autodetected from the
extension. To specify a document name, use :name as a suffix. e.g.:

    wordgrinder --convert filename.wg:"Chapter 1" chapter1.odt

The user config file is a Lua file which is loaded and executed before
the program starts up (but after any --lua files). It defaults to:

    ]] .. configfile .. [[


]])
			if DEBUG then
				-- List debugging options here.
			end
			
			os.exit(0)
		end
		
		local function do_lua(opt1, opt2)
			if not opt1 then
				CLIError("--lua must have an argument")
			end

			local f, e = loadfile(opt1)
			if e and e:find("No such file or directory") then
				f, e = loadstring(opt1)
			end
			if e then
				CLIError("user script compilation error: "..e)
			end

			f(opt2)
			os.exit(0)
		end
		
		local function do_convert(opt1, opt2)
			if not opt1 or not opt2 then
				CLIError("--convert must have two arguments")
			end
			
			CliConvert(opt1, opt2)
		end
		
		local function do_config(opt1, opt2)
			if not opt1 then
				CLIError("--config must have an argument")
			end

			configfile = opt1
			return 1
		end

		local function needarg(opt)
			if not opt then
				CLIError("missing option parameter")
			end
		end
		
		local argmap = {
			["h"]           = do_help,
			["help"]        = do_help,
			["lua"]         = do_lua,
			["c"]           = do_convert,
			["convert"]     = do_convert,
			["config"]      = do_config,
		}
		
		if DEBUG then
			-- argmap["p"] = do_profile
			-- argmap["profile"] = do_profile
		end
		 
		-- Called on an unrecognised option.
		
		local function unrecognisedarg(arg)
			CLIError("unrecognised option '", arg, "' --- try --help for help")
		end
		
		-- Do the actual argument parsing.
		
		local arg = {...}
		local i = 2
		while (i <= #arg) do
			local o = arg[i]
			local op
			
			if (o:byte(1) == 45) then
				-- This is an option.
				if (o:byte(2) == 45) then
					-- ...with a -- prefix.
					o = o:sub(3)
					local fn = argmap[o]
					if not fn then
						unrecognisedarg("--"..o)
					end
					i = i + fn(arg[i+1], arg[i+2])
				else
					-- ...without a -- prefix.
					local od = o:sub(2, 2)
					local fn = argmap[od]
					if not fn then
						unrecognisedarg("-"..od)
					end
					op = o:sub(3)
					if (op == "") then
						i = i + fn(arg[i+1], arg[i+2])
					else
						fn(op)
					end
				end
			else
				if filename then
					CLIError("you may only specify one filename")
				end
				filename = o
			end	

			i = i + 1
		end
	end
	
	if filename and
			not filename:find("^/") and
			not filename:find("^[a-zA-Z]:[/\\]") then
		filename = lfs.currentdir() .. "/" .. filename
	end
	
	WordProcessor(filename)
end

{'fraction_non_alphanumeric': 0.1048942136120316, 'fraction_numerical': 0.00650012745347948, 'mean_word_length': 2.687265037593985, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5157315', 'n_tokens_mistral': 6225, 'n_tokens_neox': 5059, 'n_words': 1705}