<commit_before>require "util"

-- Name of the row headers we put in the UI
local filterUiElementName = "FilterFillRow"
local requestUiElementName = "RequestRow"

-- Button click dispatching
local Buttons = {}
local dispatch = {}

-- How many logistic request slots a requester chest has. Replace
-- with a function once the API can tell us this
-- TODO: How to get the number of request slots?
local REQUEST_SLOTS = 10

-- Initializes the world
function startup()
    script.on_event(defines.events.on_tick, checkOpened)
    initButtons()
end

-- Listener for events clicked
function handleButton(event)
    local handler = dispatch[event.element.name]
    if handler then
        handler(game.players[event.player_index])
    end
end

-- Initializes event handlers and button names
function initButtons()
    function register(category, name, func)
        local buttonName = category .. '_' .. name
        Buttons[category][name] = buttonName
        dispatch[buttonName] = func
    end
    -- Filtering
    Buttons.Filter = {}
    register('Filter', 'All', filter_fillAll)
    register('Filter', 'Right', filter_fillRight)
    register('Filter', 'Down', filter_fillDown)
    register('Filter', 'Clear', filter_clearAll)
    register('Filter', 'Set', filter_setAll)
    -- Logistic Requests
    Buttons.Requests = {}
    register('Requests', 'x2', requests_x2)
    register('Requests', 'x5', requests_x5)
    register('Requests', 'x10', requests_x10)
    register('Requests', 'Fill', requests_fill)
    register('Requests', 'Blueprint', requests_blueprint)

    script.on_event(defines.events.on_gui_click, handleButton)
end

function canFilter(obj)
    return obj.get_output_inventory() ~= nil and obj.get_output_inventory().supports_filters()
end

function canRequest(obj)
    return obj.request_slot_count > 0
end

-- See if an applicable container is opened and show/hide the UI accordingly.
-- Some delay is imperceptible here, so only check this once every few ticks
-- to avoid performance impact

-- Initialize this to a nonzero number so every mod in the universe doesn't
-- do its expensive work on the same tick
local tickCounter = 6;
function checkOpened()
    tickCounter = tickCounter + 1
    -- 1/5 second delay doesn't seem to be noticeable
    if tickCounter == 12 then
        tickCounter = 0
    else
        return
    end

    for _, player in pairs(game.players) do
        showOrHideFilterUI(player, player.opened ~= nil and canFilter(player.opened))
        showOrHideRequestUI(player, player.opened ~= nil and canRequest(player.opened))
    end
end

-- Gets the name of the item at the given position, or nil if there
-- is no item at that position
function getItemAtPosition(player, n)
    local inv = player.opened.get_output_inventory()
    local isEmpty = not inv[n].valid_for_read
    if isEmpty then
        return nil
    else
        return inv[n].name
    end
end

-- Returns either the item at a position, or the filter
-- at the position if there isn't an item there
function getItemOrFilterAtPosition(player, n)
    local filter = player.opened.get_filter(n)
    if filter ~= nil then
        return filter
    else
        return getItemAtPosition(player, n)
    end
end

-- Filtering: Clear all filters in the opened container
function filter_clearAll(player)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        op.set_filter(i, nil)
    end
end

-- Filtering: Set the filters of the opened container to the
-- contents of each cell
function filter_setAll(player)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        local desired = getItemAtPosition(player, i)
        op.set_filter(i, desired)
    end
end

-- Filtering: Filter all cells of the opened container with the
-- contents of the player's cursor stack, or the first item in the container,
-- or the first filter in the container
function filter_fillAll(player)
    -- Get the contents of the player's cursor stack, or the first cell
    local desired = (player.cursor_stack.valid_for_read and player.cursor_stack.name) or getItemOrFilterAtPosition(player, 1)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        local current = getItemAtPosition(player, i)
        if current and desired and current ~= desired then
            player.print({"", 'Skipped setting a filter on the cell occupied by ', {'item-name.' .. current}})
        else
            op.set_filter(i, desired or nil)
        end
    end
end

-- Filtering: Copies the filter settings of each cell to the cell(s) to the right of it
function filter_fillRight(player)
    local columns = 10 -- TODO: Figure out generic way to determine columns

    local op = player.opened.get_output_inventory()
    local size = #op

    local rows = math.ceil(size / columns)
    for r = 1, rows do
        local desired = getItemOrFilterAtPosition(player, 1 + (r - 1) * columns)
        for c = 1, columns do
            local i = c + (r - 1) * columns
            if i <= size then
                desired = getItemAtPosition(player, i) or desired
                op.set_filter(i, desired)
            end
        end
    end
end

-- Filtering: Copies the filter settings of each cell to the cell(s) below it
function filter_fillDown(player)
    local columns = 10 -- TODO: Figure out generic way to determine columns

    local op = player.opened.get_output_inventory()
    local size = #op

    local rows = math.ceil(size / columns)
    for c = 1, columns do
        local desired = getItemOrFilterAtPosition(player, c)
        for r = 1, rows do
            local i = c + (r - 1) * columns
            if i <= size then
                desired = getItemAtPosition(player, i) or desired
                op.set_filter(c + (r - 1) * columns, desired)
            end<commit_msg>Make inventory columns a global constant<commit_after>require "util"

local INVENTORY_COLUMNS = 10

-- Name of the row headers we put in the UI
local filterUiElementName = "FilterFillRow"
local requestUiElementName = "RequestRow"

-- Button click dispatching
local Buttons = {}
local dispatch = {}

-- How many logistic request slots a requester chest has. Replace
-- with a function once the API can tell us this
-- TODO: How to get the number of request slots?
local REQUEST_SLOTS = 10

-- Initializes the world
function startup()
    script.on_event(defines.events.on_tick, checkOpened)
    initButtons()
end

-- Listener for events clicked
function handleButton(event)
    local handler = dispatch[event.element.name]
    if handler then
        handler(game.players[event.player_index])
    end
end

-- Initializes event handlers and button names
function initButtons()
    function register(category, name, func)
        local buttonName = category .. '_' .. name
        Buttons[category][name] = buttonName
        dispatch[buttonName] = func
    end
    -- Filtering
    Buttons.Filter = {}
    register('Filter', 'All', filter_fillAll)
    register('Filter', 'Right', filter_fillRight)
    register('Filter', 'Down', filter_fillDown)
    register('Filter', 'Clear', filter_clearAll)
    register('Filter', 'Set', filter_setAll)
    -- Logistic Requests
    Buttons.Requests = {}
    register('Requests', 'x2', requests_x2)
    register('Requests', 'x5', requests_x5)
    register('Requests', 'x10', requests_x10)
    register('Requests', 'Fill', requests_fill)
    register('Requests', 'Blueprint', requests_blueprint)

    script.on_event(defines.events.on_gui_click, handleButton)
end

function canFilter(obj)
    return obj.get_output_inventory() ~= nil and obj.get_output_inventory().supports_filters()
end

function canRequest(obj)
    return obj.request_slot_count > 0
end

-- See if an applicable container is opened and show/hide the UI accordingly.
-- Some delay is imperceptible here, so only check this once every few ticks
-- to avoid performance impact

-- Initialize this to a nonzero number so every mod in the universe doesn't
-- do its expensive work on the same tick
local tickCounter = 6;
function checkOpened()
    tickCounter = tickCounter + 1
    -- 1/5 second delay doesn't seem to be noticeable
    if tickCounter == 12 then
        tickCounter = 0
    else
        return
    end

    for _, player in pairs(game.players) do
        showOrHideFilterUI(player, player.opened ~= nil and canFilter(player.opened))
        showOrHideRequestUI(player, player.opened ~= nil and canRequest(player.opened))
    end
end

-- Gets the name of the item at the given position, or nil if there
-- is no item at that position
function getItemAtPosition(player, n)
    local inv = player.opened.get_output_inventory()
    local isEmpty = not inv[n].valid_for_read
    if isEmpty then
        return nil
    else
        return inv[n].name
    end
end

-- Returns either the item at a position, or the filter
-- at the position if there isn't an item there
function getItemOrFilterAtPosition(player, n)
    local filter = player.opened.get_filter(n)
    if filter ~= nil then
        return filter
    else
        return getItemAtPosition(player, n)
    end
end

-- Filtering: Clear all filters in the opened container
function filter_clearAll(player)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        op.set_filter(i, nil)
    end
end

-- Filtering: Set the filters of the opened container to the
-- contents of each cell
function filter_setAll(player)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        local desired = getItemAtPosition(player, i)
        op.set_filter(i, desired)
    end
end

-- Filtering: Filter all cells of the opened container with the
-- contents of the player's cursor stack, or the first item in the container,
-- or the first filter in the container
function filter_fillAll(player)
    -- Get the contents of the player's cursor stack, or the first cell
    local desired = (player.cursor_stack.valid_for_read and player.cursor_stack.name) or getItemOrFilterAtPosition(player, 1)
    local op = player.opened.get_output_inventory();
    local size = #op
    for i = 1, size do
        local current = getItemAtPosition(player, i)
        if current and desired and current ~= desired then
            player.print({"", 'Skipped setting a filter on the cell occupied by ', {'item-name.' .. current}})
        else
            op.set_filter(i, desired or nil)
        end
    end
end

-- Filtering: Copies the filter settings of each cell to the cell(s) to the right of it
function filter_fillRight(player)
    local op = player.opened.get_output_inventory()
    local size = #op

    local rows = math.ceil(size / INVENTORY_COLUMNS)
    for r = 1, rows do
        local desired = getItemOrFilterAtPosition(player, 1 + (r - 1) * INVENTORY_COLUMNS)
        for c = 1, INVENTORY_COLUMNS do
            local i = c + (r - 1) * INVENTORY_COLUMNS
            if i <= size then
                desired = getItemAtPosition(player, i) or desired
                op.set_filter(i, desired)
            end
        end
    end
end

-- Filtering: Copies the filter settings of each cell to the cell(s) below it
function filter_fillDown(player)
    local op = player.opened.get_output_inventory()
    local size = #op

    local rows = math.ceil(size / INVENTORY_COLUMNS)
    for c = 1, INVENTORY_COLUMNS do
        local desired = getItemOrFilterAtPosition(player, c)
        for r = 1, rows do
            local i = c + (r - 1) * INVENTORY_COLUMNS
            if i <= size then
                desired = getItemAtPosition(player, i) or desired
                op.set_filter(c + (r - 1) * INVENTORY_COLUMNS, desired)
            end
{'fraction_non_alphanumeric': 0.08387864366448543, 'fraction_numerical': 0.00577887311974165, 'mean_word_length': 2.958291288261016, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '558192', 'n_tokens_mistral': 3445, 'n_tokens_neox': 3347, 'n_words': 1237}