mirror of
https://github.com/hyprwm/Hyprland.git
synced 2026-08-18 02:51:23 +00:00
hyprctl: random Lua-adjacent fixes (#15767)
* hyprctl(repl): go interactive if no Lua was given via args The previous check would mess up if `-i` was provided, since it'd see *an argument* and refuse to go interactive, even when it should've (i.e. `hyprctl -i 0 repl`). * ipc(socket1): new escape parsing for batch commands Semicolons are still the command separator, so those have to be escaped if they appear anywhere inside of commands (e.g. multi-statement Lua code). Also, literal backslashes need to be escaped as well. * tests(ipc): add test for hyprctl batch mode This test case includes slightly weird stuff (semicolons in Lua code; square brackets) that would break the old parsing logic. * format: dang braces
This commit is contained in:
@ -566,8 +566,8 @@ int main(int argc, char** argv) {
|
||||
std::println("{}", USAGE);
|
||||
else if (fullRequest.contains("/rollinglog") && needRoll)
|
||||
exitStatus = request(fullRequest, 0, true);
|
||||
else if (fullRequest.contains("/repl")) {
|
||||
if (ARGS.size() > 1) {
|
||||
else if (auto pos = fullRequest.find("/repl"); pos != std::string::npos) {
|
||||
if (fullRequest.length() > pos + 5) {
|
||||
// single command with output
|
||||
exitStatus = request(fullRequest, 1);
|
||||
} else {
|
||||
|
||||
@ -206,3 +206,16 @@ TEST_CASE(hyprctlREPL) {
|
||||
EXPECT(getCommandStdOut("hyprctl repl 'print(type(hl))'"), "table");
|
||||
EXPECT(getCommandStdOut("hyprctl eval 'print(type(hl))'"), "ok");
|
||||
}
|
||||
|
||||
TEST_CASE(hyprctlBatch) {
|
||||
const auto command = R"([[BATCH]] activewindow; repl local i = 42\; print(i, "hello\\nworld ]"); clients)";
|
||||
const auto expected = R"(Invalid
|
||||
|
||||
|
||||
42 hello
|
||||
world ]
|
||||
|
||||
|
||||
no open windows)";
|
||||
EXPECT(getFromSocket(command), expected);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
||||
using namespace IPC::Socket1;
|
||||
@ -129,25 +130,24 @@ SResponse CSocket1::dispatchBatch(std::string request, pid_t pid) {
|
||||
request = request.substr(BATCH_TOKEN.size());
|
||||
|
||||
std::vector<std::string> commands;
|
||||
size_t commandStart = 0;
|
||||
int bracketDepth = 0;
|
||||
std::stringstream parsedCommand("");
|
||||
|
||||
for (size_t i = 0; i <= request.size(); ++i) {
|
||||
const bool atEnd = i == request.size();
|
||||
|
||||
if (!atEnd) {
|
||||
if (request[i] == '[')
|
||||
++bracketDepth;
|
||||
else if (request[i] == ']')
|
||||
--bracketDepth;
|
||||
if (atEnd || request[i] == ';') {
|
||||
commands.emplace_back(Hyprutils::String::trim(parsedCommand.str()));
|
||||
parsedCommand.str("");
|
||||
parsedCommand.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!atEnd && (request[i] != ';' || bracketDepth != 0))
|
||||
continue;
|
||||
|
||||
if (commandStart < i)
|
||||
commands.emplace_back(Hyprutils::String::trim(request.substr(commandStart, i - commandStart)));
|
||||
commandStart = i + 1;
|
||||
if (request[i] == '\\') {
|
||||
if (i < request.size() && (request[i + 1] == '\\' || request[i + 1] == ';'))
|
||||
++i;
|
||||
else
|
||||
Log::logger->log(Log::ERR, "Malformed socket1 request: invalid escape sequence {} at position {}, using it verbatim", request.subview(i, 2), i);
|
||||
}
|
||||
parsedCommand << request[i];
|
||||
}
|
||||
|
||||
std::vector<SResponse> responses;
|
||||
|
||||
Reference in New Issue
Block a user