function table_to_string(tbl)
    local result = "{"
    for k, v in pairs(tbl) do
        -- Check the key type (ignore any numerical keys - assume its an array)
        if type(k) == "string" then
            result = result.."[\""..k.."\"]".."="
        end

        -- Check the value type
        if type(v) == "table" then
            result = result..table_to_string(v)
        elseif type(v) == "boolean" then
            result = result..tostring(v)
        else
            result = result.."\""..v.."\""
        end
        result = result..","
    end
    -- Remove leading commas from the result
    if result ~= "" then
        result = result:sub(1, result:len()-1)
    end
    return result.."}"
end

local offset;
mle.editor_register_observer("cmd:cmd_save:before", function (ctx)
  offset = mle.mark_get_offset(ctx["mark"], 0);
  local buf = mle.buffer_get(ctx["buffer"])["ret_data"];
  local result = buf:gsub("[ \t]+%f[\r\n%z]", "");
  result = result:match("^%s*(.-)%s*$") .. "\n";
  mle.buffer_set(ctx["buffer"], result, string.len(result));
end)

mle.editor_register_observer("cmd:cmd_save:after", function (ctx)
  mle.mark_move_offset(ctx["mark"], offset["ret_offset"]);
  mle.bview_center_viewport_y(ctx["bview"]);
end)

mle.editor_register_cmd("cmd_lua_test", function (ctx)
    name = mle.editor_prompt("Enter your name")
    if name then
        print("hello <" .. name .. "> from lua")
    else
        print("you hit cancel")
    end
end)

mle.editor_register_cmd("cmd_delete_forward_to_char", function (ctx)
  local c = utf8.char(ctx["wildcard_params"][0]);
  mle.cursor_drop_anchor(ctx["cursor"], 0);
  mle.mark_move_next_str(ctx["mark"], c, string.len(c));
  mle.cursor_cut_copy(ctx["cursor"], 1, 0, 0);
end)

mle.editor_register_cmd("cmd_delete_back_to_char", function (ctx)
  local c = utf8.char(ctx["wildcard_params"][0]);
  mle.cursor_drop_anchor(ctx["cursor"], 0);
  mle.mark_move_prev_str(ctx["mark"], c, string.len(c));
  mle.cursor_cut_copy(ctx["cursor"], 1, 0, 0);
end)
