diff --git a/completions/bash/riverctl b/completions/bash/riverctl index f3d8674..395c6f2 100644 --- a/completions/bash/riverctl +++ b/completions/bash/riverctl @@ -1,5 +1,6 @@ function __riverctl_completion () { + local rule_actions="float no-float ssd csd tag" if [ "${COMP_CWORD}" -eq 1 ] then OPTS=" \ @@ -63,7 +64,7 @@ function __riverctl_completion () "focus-view"|"swap") OPTS="next previous up down left right" ;; "move"|"snap") OPTS="up down left right" ;; "resize") OPTS="horizontal vertical" ;; - "rule-add"|"rule-del") OPTS="float no-float ssd csd tag" ;; + "rule-add"|"rule-del") OPTS="-app-id -title $rule_actions" ;; "list-rules") OPTS="float ssd tag" ;; "map") OPTS="-release -repeat -layout" ;; "unmap") OPTS="-release" ;; @@ -114,6 +115,24 @@ function __riverctl_completion () "scroll-method") OPTS="none two-finger edge button" ;; *) return ;; esac + elif [ "${COMP_WORDS[1]:0:5}" == "rule-" ] + then + case "${COMP_WORDS[2]}" in + "-app-id") OPTS="-title $rule_actions" ;; + "-title") OPTS="-app-id $rule_actions" ;; + *) return ;; + esac + COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[4]}")) + fi + elif [ "${COMP_CWORD}" -eq 6 ] + then + if [ "${COMP_WORDS[1]:0:5}" == "rule-" ] + then + case "${COMP_WORDS[4]}" in + "-app-id"|"-title") OPTS="$rule_actions" ;; + *) return ;; + esac + COMPREPLY=($(compgen -W "${OPTS}" -- "${COMP_WORDS[6]}")) fi else return diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd index e08cd44..b599a90 100644 --- a/doc/riverctl.1.scd +++ b/doc/riverctl.1.scd @@ -259,7 +259,7 @@ For example, _abc_ is matched by _a\*_, _\*a\*_, _\*b\*_, _\*c_, _abc_, and _\*_ but not matched by _\*a_, _b\*_, _\*b_, _c\*_, or _ab_. Note that _\*_ matches everything while _\*\*_ and the empty string are invalid. -*rule-add* _action_ [*-app-id* _glob_|*-title* _glob_] [_argument_] +*rule-add* [*-app-id* _glob_|*-title* _glob_] _action_ [_argument_] Add a rule that applies an _action_ to views with *app-id* and *title* matched by the respective _glob_. Omitting *-app-id* or *-title* is equivalent to passing *-app-id* _\*_ or *-title* _\*_. @@ -301,7 +301,7 @@ matches everything while _\*\*_ and the empty string are invalid. wishes of the client and may start the view floating based on simple heuristics intended to catch popup-like views. -*rule-del* _action_ [*-app-id* _glob_|*-title* _glob_] +*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_ Delete a rule created using *rule-add* with the given arguments. *list-rules* *float*|*ssd*|*tag* diff --git a/example/init b/example/init index a8e120f..dff995c 100755 --- a/example/init +++ b/example/init @@ -151,10 +151,10 @@ riverctl border-color-unfocused 0x586e75 riverctl set-repeat 50 300 # Make all views with an app-id that starts with "float" and title "foo" start floating. -riverctl rule-add float -app-id 'float*' -title 'foo' +riverctl rule-add -app-id 'float*' -title 'foo' float # Make all views with app-id "bar" and any title use client-side decorations -riverctl rule-add csd -app-id "bar" +riverctl rule-add -app-id "bar" csd # Set the default layout generator to be rivertile and start it. # River will send the process group of the init executable SIGTERM on exit. diff --git a/river/command/rule.zig b/river/command/rule.zig index 87e7511..33b9b3b 100644 --- a/river/command/rule.zig +++ b/river/command/rule.zig @@ -36,20 +36,20 @@ const Action = enum { }; pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void { - if (args.len < 2) return Error.NotEnoughArguments; - const result = flags.parser([:0]const u8, &.{ .{ .name = "app-id", .kind = .arg }, .{ .name = "title", .kind = .arg }, - }).parse(args[2..]) catch { + }).parse(args[1..]) catch { return error.InvalidValue; }; - const action = std.meta.stringToEnum(Action, args[1]) orelse return Error.UnknownOption; + if (result.args.len < 1) return Error.NotEnoughArguments; + + const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption; const positional_arguments_count: u8 = switch (action) { - .float, .@"no-float", .ssd, .csd => 0, - .tag => 1, + .float, .@"no-float", .ssd, .csd => 1, + .tag => 2, }; if (result.args.len > positional_arguments_count) return Error.TooManyArguments; if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments; @@ -78,7 +78,7 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void server.root.applyPending(); }, .tag => { - const tag = try fmt.parseInt(u32, result.args[0], 10); + const tag = try fmt.parseInt(u32, result.args[1], 10); try server.config.tag_rules.add(.{ .app_id_glob = app_id_glob, .title_glob = title_glob, @@ -89,18 +89,17 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void } pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void { - if (args.len < 2) return Error.NotEnoughArguments; - const result = flags.parser([:0]const u8, &.{ .{ .name = "app-id", .kind = .arg }, .{ .name = "title", .kind = .arg }, - }).parse(args[2..]) catch { + }).parse(args[1..]) catch { return error.InvalidValue; }; - if (result.args.len > 0) return Error.TooManyArguments; + if (result.args.len > 1) return Error.TooManyArguments; + if (result.args.len < 1) return Error.NotEnoughArguments; - const action = std.meta.stringToEnum(Action, args[1]) orelse return Error.UnknownOption; + const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption; const app_id_glob = result.flags.@"app-id" orelse "*"; const title_glob = result.flags.title orelse "*";