river: add tags rule

This commit is contained in:
Leon Henrik Plickat 2023-06-27 02:11:13 +02:00
parent a98de941d0
commit 0b142bd16b
7 changed files with 54 additions and 13 deletions

View File

@ -62,8 +62,8 @@ function __riverctl_completion ()
"focus-output"|"focus-view"|"send-to-output"|"swap") OPTS="next previous" ;; "focus-output"|"focus-view"|"send-to-output"|"swap") OPTS="next previous" ;;
"move"|"snap") OPTS="up down left right" ;; "move"|"snap") OPTS="up down left right" ;;
"resize") OPTS="horizontal vertical" ;; "resize") OPTS="horizontal vertical" ;;
"rule-add"|"rule-del") OPTS="float no-float ssd csd" ;; "rule-add"|"rule-del") OPTS="float no-float ssd csd tag" ;;
"list-rules") OPTS="float ssd" ;; "list-rules") OPTS="float ssd tag" ;;
"map") OPTS="-release -repeat -layout" ;; "map") OPTS="-release -repeat -layout" ;;
"unmap") OPTS="-release" ;; "unmap") OPTS="-release" ;;
"attach-mode") OPTS="top bottom" ;; "attach-mode") OPTS="top bottom" ;;

View File

@ -83,9 +83,9 @@ complete -c riverctl -x -n '__fish_seen_subcommand_from unmap' -a
complete -c riverctl -x -n '__fish_seen_subcommand_from attach-mode' -a 'top bottom' complete -c riverctl -x -n '__fish_seen_subcommand_from attach-mode' -a 'top bottom'
complete -c riverctl -x -n '__fish_seen_subcommand_from focus-follows-cursor' -a 'disabled normal always' complete -c riverctl -x -n '__fish_seen_subcommand_from focus-follows-cursor' -a 'disabled normal always'
complete -c riverctl -x -n '__fish_seen_subcommand_from set-cursor-warp' -a 'disabled on-output-change on-focus-change' complete -c riverctl -x -n '__fish_seen_subcommand_from set-cursor-warp' -a 'disabled on-output-change on-focus-change'
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-add' -a 'float no-float ssd csd' complete -c riverctl -x -n '__fish_seen_subcommand_from rule-add' -a 'float no-float ssd csd tag'
complete -c riverctl -x -n '__fish_seen_subcommand_from rule-del' -a 'float no-float ssd csd' complete -c riverctl -x -n '__fish_seen_subcommand_from rule-del' -a 'float no-float ssd csd tag'
complete -c riverctl -x -n '__fish_seen_subcommand_from list-rules' -a 'float ssd' complete -c riverctl -x -n '__fish_seen_subcommand_from list-rules' -a 'float ssd tag'
# Subcommands for 'input' # Subcommands for 'input'
complete -c riverctl -x -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 2' -a "(__riverctl_list_input_devices)" complete -c riverctl -x -n '__fish_seen_subcommand_from input; and __fish_riverctl_complete_arg 2' -a "(__riverctl_list_input_devices)"

View File

@ -183,9 +183,9 @@ _riverctl()
focus-follows-cursor) _alternative 'arguments:args:(disabled normal always)' ;; focus-follows-cursor) _alternative 'arguments:args:(disabled normal always)' ;;
set-cursor-warp) _alternative 'arguments:args:(disabled on-output-change on-focus-change)' ;; set-cursor-warp) _alternative 'arguments:args:(disabled on-output-change on-focus-change)' ;;
hide-cursor) _riverctl_hide_cursor ;; hide-cursor) _riverctl_hide_cursor ;;
rule-add) _alternative 'arguments:args:(float no-float ssd csd)' ;; rule-add) _alternative 'arguments:args:(float no-float ssd csd tag)' ;;
rule-del) _alternative 'arguments:args:(float no-float ssd csd)' ;; rule-del) _alternative 'arguments:args:(float no-float ssd csd tag)' ;;
list-rules) _alternative 'arguments:args:(float ssd)' ;; list-rules) _alternative 'arguments:args:(float ssd tag)' ;;
*) return 0 ;; *) return 0 ;;
esac esac
;; ;;

View File

@ -258,10 +258,11 @@ For example, _abc_ is matched by _a\*_, _\*a\*_, _\*b\*_, _\*c_, _abc_, and
_\*_ but not matched by _\*a_, _b\*_, _\*b_, _c\*_, or _ab_. Note that _\*_ _\*_ but not matched by _\*a_, _b\*_, _\*b_, _c\*_, or _ab_. Note that _\*_
matches everything while _\*\*_ and the empty string are invalid. matches everything while _\*\*_ and the empty string are invalid.
*rule-add* _action_ [*-app-id* _glob_|*-title* _glob_] *rule-add* _action_ [*-app-id* _glob_|*-title* _glob_] [_argument_]
Add a rule that applies an _action_ to views with *app-id* and *title* Add a rule that applies an _action_ to views with *app-id* and *title*
matched by the respective _glob_. Omitting *-app-id* or *-title* matched by the respective _glob_. Omitting *-app-id* or *-title*
is equivalent to passing *-app-id* _\*_ or *-title* _\*_. is equivalent to passing *-app-id* _\*_ or *-title* _\*_.
Some actions require an _argument_.
The supported _action_ types are: The supported _action_ types are:
@ -272,6 +273,8 @@ matches everything while _\*\*_ and the empty string are invalid.
and existing views. and existing views.
- *csd*: Use client-side decorations for the view. Applies to new - *csd*: Use client-side decorations for the view. Applies to new
and existing views. and existing views.
- *tag*: Set the initial tags of the view. Requires the tags as
an argument. Applies only to new views.
Both *float* and *no-float* rules are added to the same list, Both *float* and *no-float* rules are added to the same list,
which means that adding a *no-float* rule with the same arguments which means that adding a *no-float* rule with the same arguments
@ -300,7 +303,7 @@ matches everything while _\*\*_ and the empty string are invalid.
*rule-del* _action_ [*-app-id* _glob_|*-title* _glob_] *rule-del* _action_ [*-app-id* _glob_|*-title* _glob_]
Delete a rule created using *rule-add* with the given arguments. Delete a rule created using *rule-add* with the given arguments.
*list-rules* *float*|*ssd* *list-rules* *float*|*ssd*|*tag*
Print the specified rule list. The output is ordered from most specific Print the specified rule list. The output is ordered from most specific
to least specific, the same order in which views are checked against to least specific, the same order in which views are checked against
when searching for a match. Only the first matching rule in the list when searching for a match. Only the first matching rule in the list

View File

@ -75,6 +75,7 @@ modes: std.ArrayListUnmanaged(Mode),
float_rules: RuleList(bool) = .{}, float_rules: RuleList(bool) = .{},
ssd_rules: RuleList(bool) = .{}, ssd_rules: RuleList(bool) = .{},
tag_rules: RuleList(u32) = .{},
/// The selected focus_follows_cursor mode /// The selected focus_follows_cursor mode
focus_follows_cursor: FocusFollowsCursorMode = .disabled, focus_follows_cursor: FocusFollowsCursorMode = .disabled,
@ -150,6 +151,7 @@ pub fn deinit(self: *Self) void {
self.float_rules.deinit(); self.float_rules.deinit();
self.ssd_rules.deinit(); self.ssd_rules.deinit();
self.tag_rules.deinit();
util.gpa.free(self.default_layout_namespace); util.gpa.free(self.default_layout_namespace);

View File

@ -508,6 +508,7 @@ pub fn map(view: *Self) !void {
view.pending.box.y = @divTrunc(math.max(0, output.usable_box.height - view.pending.box.height), 2); view.pending.box.y = @divTrunc(math.max(0, output.usable_box.height - view.pending.box.height), 2);
view.pending.tags = blk: { view.pending.tags = blk: {
if (server.config.tag_rules.match(view)) |tags| break :blk tags;
const tags = output.pending.tags & server.config.spawn_tagmask; const tags = output.pending.tags & server.config.spawn_tagmask;
break :blk if (tags != 0) tags else output.pending.tags; break :blk if (tags != 0) tags else output.pending.tags;
}; };

View File

@ -32,6 +32,7 @@ const Action = enum {
@"no-float", @"no-float",
ssd, ssd,
csd, csd,
tag,
}; };
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void { pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
@ -44,9 +45,14 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
return error.InvalidValue; return error.InvalidValue;
}; };
if (result.args.len > 0) return Error.TooManyArguments;
const action = std.meta.stringToEnum(Action, args[1]) orelse return Error.UnknownOption; const action = std.meta.stringToEnum(Action, args[1]) orelse return Error.UnknownOption;
const positional_arguments_count: u8 = switch (action) {
.float, .@"no-float", .ssd, .csd => 0,
.tag => 1,
};
if (result.args.len > positional_arguments_count) return Error.TooManyArguments;
const app_id_glob = result.flags.@"app-id" orelse "*"; const app_id_glob = result.flags.@"app-id" orelse "*";
const title_glob = result.flags.title orelse "*"; const title_glob = result.flags.title orelse "*";
@ -70,6 +76,14 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
apply_ssd_rules(); apply_ssd_rules();
server.root.applyPending(); server.root.applyPending();
}, },
.tag => {
const tag = try fmt.parseInt(u32, result.args[0], 10);
try server.config.tag_rules.add(.{
.app_id_glob = app_id_glob,
.title_glob = title_glob,
.value = tag,
});
},
} }
} }
@ -104,6 +118,12 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
apply_ssd_rules(); apply_ssd_rules();
server.root.applyPending(); server.root.applyPending();
}, },
.tag => {
server.config.tag_rules.del(.{
.app_id_glob = app_id_glob,
.title_glob = title_glob,
});
},
} }
} }
@ -120,10 +140,15 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
if (args.len < 2) return error.NotEnoughArguments; if (args.len < 2) return error.NotEnoughArguments;
if (args.len > 2) return error.TooManyArguments; if (args.len > 2) return error.TooManyArguments;
const list = std.meta.stringToEnum(enum { float, ssd }, args[1]) orelse return Error.UnknownOption; const list = std.meta.stringToEnum(enum {
float,
ssd,
tag,
}, args[1]) orelse return Error.UnknownOption;
const max_glob_len = switch (list) { const max_glob_len = switch (list) {
.float => server.config.float_rules.getMaxGlobLen(), .float => server.config.float_rules.getMaxGlobLen(),
.ssd => server.config.ssd_rules.getMaxGlobLen(), .ssd => server.config.ssd_rules.getMaxGlobLen(),
.tag => server.config.tag_rules.getMaxGlobLen(),
}; };
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id); const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
const title_column_max = 2 + @max("title".len, max_glob_len.title); const title_column_max = 2 + @max("title".len, max_glob_len.title);
@ -140,6 +165,7 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
const rules = switch (list) { const rules = switch (list) {
.float => server.config.float_rules.rules.items, .float => server.config.float_rules.rules.items,
.ssd => server.config.ssd_rules.rules.items, .ssd => server.config.ssd_rules.rules.items,
else => unreachable,
}; };
for (rules) |rule| { for (rules) |rule| {
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .Left }, writer); try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .Left }, writer);
@ -147,9 +173,18 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
try writer.print("{s}\n", .{switch (list) { try writer.print("{s}\n", .{switch (list) {
.float => if (rule.value) "float" else "no-float", .float => if (rule.value) "float" else "no-float",
.ssd => if (rule.value) "ssd" else "csd", .ssd => if (rule.value) "ssd" else "csd",
else => unreachable,
}}); }});
} }
}, },
.tag => {
const rules = server.config.tag_rules.rules.items;
for (rules) |rule| {
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .Left }, writer);
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .Left }, writer);
try writer.print("{b}\n", .{rule.value});
}
},
} }
out.* = buffer.toOwnedSlice(); out.* = buffer.toOwnedSlice();