aboutsummaryrefslogtreecommitdiff
path: root/src/command.zig
blob: 39b8b79b7fb1f69f6e3a5e8d72afd7e1a3569918 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// This file is part of river, a dynamic tiling wayland compositor.
//
// Copyright 2020 Isaac Freund
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

const std = @import("std");

const Seat = @import("Seat.zig");

const impl = struct {
    const close = @import("command/close.zig").close;
    const exit = @import("command/exit.zig").exit;
    const focus = @import("command/focus.zig").focus;
    const focusAllTags = @import("command/focus_all_tags.zig").focusAllTags;
    const focusOutput = @import("command/focus_output.zig").focusOutput;
    const focusTag = @import("command/focus_tag.zig").focusTag;
    const layout = @import("command/layout.zig").layout;
    const modMasterCount = @import("command/mod_master_count.zig").modMasterCount;
    const modMasterFactor = @import("command/mod_master_factor.zig").modMasterFactor;
    const mode = @import("command/mode.zig").mode;
    const sendToOutput = @import("command/send_to_output.zig").sendToOutput;
    const spawn = @import("command/spawn.zig").spawn;
    const tagView = @import("command/tag_view.zig").tagView;
    const tagViewAllTags = @import("command/tag_view_all_tags.zig").tagViewAllTags;
    const toggleFloat = @import("command/toggle_float.zig").toggleFloat;
    const toggleTagFocus = @import("command/toggle_tag_focus.zig").toggleTagFocus;
    const toggleViewTag = @import("command/toggle_view_tag.zig").toggleViewTag;
    const zoom = @import("command/zoom.zig").zoom;
};

pub const Direction = enum {
    Next,
    Prev,

    pub fn parse(str: []const u8) error{InvalidDirection}!Direction {
        return if (std.mem.eql(u8, str, "next"))
            Direction.Next
        else if (std.mem.eql(u8, str, "previous"))
            Direction.Prev
        else
            error.InvalidDirection;
    }
};

const Definition = struct {
    name: []const u8,
    impl: fn (*std.mem.Allocator, *Seat, []const []const u8, *[]const u8) Error!void,
};

// TODO: this could be replaced with a comptime hashmap
// zig fmt: off
const str_to_impl_fn = [_]Definition{
    .{ .name = "close",             .impl = impl.close },
    .{ .name = "exit",              .impl = impl.exit },
    .{ .name = "focus",             .impl = impl.focus },
    .{ .name = "focus_all_tags",    .impl = impl.focusAllTags },
    .{ .name = "focus_output",      .impl = impl.focusOutput },
    .{ .name = "focus_tag",         .impl = impl.focusTag },
    .{ .name = "layout",            .impl = impl.layout},
    .{ .name = "mod_master_count",  .impl = impl.modMasterCount },
    .{ .name = "mod_master_factor", .impl = impl.modMasterFactor },
    .{ .name = "mode",              .impl = impl.mode },
    .{ .name = "send_to_output",    .impl = impl.sendToOutput },
    .{ .name = "spawn",             .impl = impl.spawn },
    .{ .name = "tag_view",          .impl = impl.tagView },
    .{ .name = "tag_view_all_tags", .impl = impl.tagViewAllTags },
    .{ .name = "toggle_float",      .impl = impl.toggleFloat },
    .{ .name = "toggle_tag_focus",  .impl = impl.toggleTagFocus },
    .{ .name = "toggle_view_tag",   .impl = impl.toggleViewTag },
    .{ .name = "zoom",              .impl = impl.zoom },
};
// zig fmt: on

pub const Error = error{
    NoCommand,
    UnknownCommand,
    NotEnoughArguments,
    TooManyArguments,
    Overflow,
    InvalidCharacter,
    InvalidDirection,
    OutOfMemory,
    CommandFailed,
};

/// Run a command for the given Seat. The `args` parameter is similar to the
/// classic argv in that the command to be run is passed as the first argument.
/// If the command fails with Error.CommandFailed, a failure message will be
/// allocated and the slice pointed to by the `failure_message` parameter will
/// be set to point to it. The caller is responsible for freeing this message
/// in the case of failure.
pub fn run(
    allocator: *std.mem.Allocator,
    seat: *Seat,
    args: []const []const u8,
    failure_message: *[]const u8,
) Error!void {
    if (args.len == 0) return Error.NoCommand;

    const name = args[0];
    const impl_fn = for (str_to_impl_fn) |definition| {
        if (std.mem.eql(u8, name, definition.name)) break definition.impl;
    } else return Error.UnknownCommand;

    try impl_fn(allocator, seat, args, failure_message);
}