diff options
| author | Isaac Freund <mail@isaacfreund.com> | 2022-12-28 21:56:42 +0100 |
|---|---|---|
| committer | Isaac Freund <mail@isaacfreund.com> | 2022-12-28 21:56:42 +0100 |
| commit | 2be9ac05d6ec1994a2dab1d5d2db979513bb94f2 (patch) | |
| tree | 444197e7f1329f5c362f27cab173898b8c823ea7 | |
| parent | eed7d94557e38becea84010b5b7e615bdbdd89af (diff) | |
| download | river-2be9ac05d6ec1994a2dab1d5d2db979513bb94f2.tar.gz river-2be9ac05d6ec1994a2dab1d5d2db979513bb94f2.tar.xz | |
command/map: use flags.zig, cleanup
| -rw-r--r-- | river/Mapping.zig | 31 | ||||
| -rw-r--r-- | river/Seat.zig | 2 | ||||
| -rw-r--r-- | river/command/map.zig | 118 |
3 files changed, 64 insertions, 87 deletions
diff --git a/river/Mapping.zig b/river/Mapping.zig index 94ea2a4..9e898bb 100644 --- a/river/Mapping.zig +++ b/river/Mapping.zig @@ -25,24 +25,23 @@ const util = @import("util.zig"); keysym: xkb.Keysym, modifiers: wlr.Keyboard.ModifierMask, command_args: []const [:0]const u8, +options: Options, -// This is set for mappings with layout-pinning -// If set, the layout with this index is always used to translate the given keycode -layout_index: ?u32, - -/// When set to true the mapping will be executed on key release rather than on press -release: bool, - -/// When set to true the mapping will be executed repeatedly while key is pressed -repeat: bool, +pub const Options = struct { + /// When set to true the mapping will be executed on key release rather than on press + release: bool, + /// When set to true the mapping will be executed repeatedly while key is pressed + repeat: bool, + // This is set for mappings with layout-pinning + // If set, the layout with this index is always used to translate the given keycode + layout_index: ?u32, +}; pub fn init( keysym: xkb.Keysym, modifiers: wlr.Keyboard.ModifierMask, - release: bool, - repeat: bool, - layout_index: ?u32, command_args: []const []const u8, + options: Options, ) !Self { const owned_args = try util.gpa.alloc([:0]u8, command_args.len); errdefer util.gpa.free(owned_args); @@ -53,10 +52,8 @@ pub fn init( return Self{ .keysym = keysym, .modifiers = modifiers, - .release = release, - .repeat = repeat, - .layout_index = layout_index, .command_args = owned_args, + .options = options, }; } @@ -73,14 +70,14 @@ pub fn match( released: bool, xkb_state: *xkb.State, ) bool { - if (released != self.release) return false; + if (released != self.options.release) return false; const keymap = xkb_state.getKeymap(); // If the mapping has no pinned layout, use the active layout. // It doesn't matter if the index is out of range, since xkbcommon // will fall back to the active layout if so. - const layout_index = self.layout_index orelse xkb_state.keyGetLayout(keycode); + const layout_index = self.options.layout_index orelse xkb_state.keyGetLayout(keycode); // Get keysyms from the base layer, as if modifiers didn't change keysyms. // E.g. pressing `Super+Shift 1` does not translate to `Super Exclam`. diff --git a/river/Seat.zig b/river/Seat.zig index 05110ce..fae8150 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -395,7 +395,7 @@ pub fn handleMapping( var handled = false; for (modes.items[self.mode_id].mappings.items) |*mapping| { if (mapping.match(keycode, modifiers, released, xkb_state)) { - if (mapping.repeat) { + if (mapping.options.repeat) { self.repeating_mapping = mapping; self.mapping_repeat_timer.timerUpdate(server.config.repeat_delay) catch { log.err("failed to update mapping repeat timer", .{}); diff --git a/river/command/map.zig b/river/command/map.zig index 398e12d..1d63f85 100644 --- a/river/command/map.zig +++ b/river/command/map.zig @@ -20,6 +20,7 @@ const mem = std.mem; const meta = std.meta; const wlr = @import("wlroots"); const xkb = @import("xkbcommon"); +const flags = @import("flags"); const c = @import("../c.zig"); const server = &@import("../main.zig").server; @@ -41,16 +42,29 @@ pub fn map( args: []const [:0]const u8, out: *?[]const u8, ) Error!void { - const optionals = try parseOptionalArgs(args[1..]); - // offset caused by optional arguments - const offset = optionals.i; - if (args.len - offset < 5) return Error.NotEnoughArguments; + const result = flags.parser([:0]const u8, &.{ + .{ .name = "-release", .kind = .boolean }, + .{ .name = "-repeat", .kind = .boolean }, + .{ .name = "-layout", .kind = .arg }, + }).parse(args[1..]) catch { + return error.InvalidValue; + }; + if (result.args.len < 4) return Error.NotEnoughArguments; + + if (result.flags.@"-release" and result.flags.@"-repeat") return Error.ConflictingOptions; - if (optionals.release and optionals.repeat) return Error.ConflictingOptions; + const layout_index = blk: { + if (result.flags.@"-layout") |layout_raw| { + break :blk try fmt.parseInt(u32, layout_raw, 10); + } else { + break :blk null; + } + }; - const mode_raw = args[1 + offset]; - const modifiers_raw = args[2 + offset]; - const keysym_raw = args[3 + offset]; + const mode_raw = result.args[0]; + const modifiers_raw = result.args[1]; + const keysym_raw = result.args[2]; + const command = result.args[3..]; const mode_id = try modeNameToId(mode_raw, out); const modifiers = try parseModifiers(modifiers_raw, out); @@ -61,18 +75,20 @@ pub fn map( const new = try Mapping.init( keysym, modifiers, - optionals.release, - optionals.repeat, - optionals.layout_index, - args[4 + offset ..], + command, + .{ + .release = result.flags.@"-release", + .repeat = result.flags.@"-repeat", + .layout_index = layout_index, + }, ); errdefer new.deinit(); - if (mappingExists(mode_mappings, modifiers, keysym, optionals.release)) |current| { + if (mappingExists(mode_mappings, modifiers, keysym, result.flags.@"-release")) |current| { mode_mappings.items[current].deinit(); mode_mappings.items[current] = new; // Warn user if they overwrote an existing keybinding using riverctl. - const opts = if (optionals.release) "-release " else ""; + const opts = if (result.flags.@"-release") "-release " else ""; out.* = try fmt.allocPrint( util.gpa, "overwrote an existing keybinding: {s} {s}{s} {s}", @@ -185,7 +201,9 @@ fn mappingExists( release: bool, ) ?usize { for (mappings.items) |mapping, i| { - if (meta.eql(mapping.modifiers, modifiers) and mapping.keysym == keysym and mapping.release == release) { + if (meta.eql(mapping.modifiers, modifiers) and + mapping.keysym == keysym and mapping.options.release == release) + { return i; } } @@ -321,68 +339,30 @@ fn parseSwitchState( } } -const OptionalArgsContainer = struct { - i: usize, - release: bool, - repeat: bool, - layout_index: ?u32, -}; - -/// Parses optional args (such as -release) and return the index of the first argument that is -/// not an optional argument -/// Returns an OptionalArgsContainer with the settings set according to the args -fn parseOptionalArgs(args: []const []const u8) !OptionalArgsContainer { - // Set to defaults - var parsed = OptionalArgsContainer{ - // i is the number of arguments consumed - .i = 0, - .release = false, - .repeat = false, - .layout_index = null, - }; - - var j: usize = 0; - while (j < args.len) : (j += 1) { - if (mem.eql(u8, args[j], "-release")) { - parsed.release = true; - parsed.i += 1; - } else if (mem.eql(u8, args[j], "-repeat")) { - parsed.repeat = true; - parsed.i += 1; - } else if (mem.eql(u8, args[j], "-layout")) { - j += 1; - if (j == args.len) return Error.NotEnoughArguments; - // To keep things simple here, we do not check if the layout index - // is out of range. We rely on xkbcommon to handle this case: - // xkbcommon will simply use the active layout instead, leaving - // this option without effect - parsed.layout_index = try std.fmt.parseInt(u32, args[j], 10); - parsed.i += 2; - } else { - // Break if the arg is not an option - break; - } - } - - return parsed; -} - /// Remove a mapping from a given mode /// /// Example: /// unmap normal Mod4+Shift Return pub fn unmap(seat: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!void { - const optionals = try parseOptionalArgs(args[1..]); - // offset caused by optional arguments - const offset = optionals.i; - if (args.len - offset < 4) return Error.NotEnoughArguments; + const result = flags.parser([:0]const u8, &.{ + .{ .name = "-release", .kind = .boolean }, + }).parse(args[1..]) catch { + return error.InvalidValue; + }; + if (result.args.len < 3) return Error.NotEnoughArguments; + if (result.args.len > 3) return Error.TooManyArguments; - const mode_id = try modeNameToId(args[1 + offset], out); - const modifiers = try parseModifiers(args[2 + offset], out); - const keysym = try parseKeysym(args[3 + offset], out); + const mode_id = try modeNameToId(result.args[0], out); + const modifiers = try parseModifiers(result.args[1], out); + const keysym = try parseKeysym(result.args[2], out); const mode_mappings = &server.config.modes.items[mode_id].mappings; - const mapping_idx = mappingExists(mode_mappings, modifiers, keysym, optionals.release) orelse return; + const mapping_idx = mappingExists( + mode_mappings, + modifiers, + keysym, + result.flags.@"-release", + ) orelse return; // Repeating mappings borrow the Mapping directly. To prevent a possible // crash if the Mapping ArrayList is reallocated, stop any currently |
