╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ bsp.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
50 var client_stdout_buffer: [256]u8 = undefined; 51 var client_stdout_writer = child_process.stdin.?.writerStreaming(io, &client_stdout_buffer); 52 53 var client: Client = .{ 54 .in = client_stdout, 55 .out = &client_stdout_writer.interface, 56 }; 57 58 const err = blk: { 59 const handshake: Server.Message.Handshake = handshake: { 60 const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { 61 error.Canceled, error.ConcurrencyUnavailable => |e| return e, 62 error.Timeout => unreachable, 63 else => |e| { 64 log.err("failed to receive message: {t}", .{err}); 65 break :blk e; 66 }, 67 }; 68 const body = client_stdout.take(header.bytes_len) catch unreachable; 69 log.debug("received {f} ({d} bytes)", .{ fmtEnum(header.tag), body.len }); 70 71 if (header.tag != .bsp_handshake) { 72 log.err("received unexpected message: {f}", .{fmtEnum(header.tag)}); 73 return error.UnexpectedMessage; 74 } 75 76 var r: Io.Reader = .fixed(body); 77 break :handshake try r.takeStruct(Server.Message.Handshake, .little); 78 }; 79 _ = handshake; 80 81 var conf_arena_allocator: std.heap.ArenaAllocator = .init(gpa); 82 defer conf_arena_allocator.deinit(); 83 const conf_arena = conf_arena_allocator.allocator(); 84 85 const configuration = configuration: { 86 const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { 87 error.Canceled, error.ConcurrencyUnavailable => |e| return e, 88 error.Timeout => unreachable, 89 else => |e| { 90 log.err("failed to receive message: {t}", .{err}); 91 break :blk e; 92 }, 93 }; 94 const body = client_stdout.take(header.bytes_len) catch unreachable; 95 log.debug("received {t} ({d} bytes)", .{ header.tag, body.len }); 96 97 if (header.tag != .bsp_configuration) { 98 log.err("received unexpected message: {f}", .{fmtEnum(header.tag)}); 99 return error.UnexpectedMessage; 100 } 101 102 const configuration_path = body; 103 var file = Io.Dir.cwd().openFile(io, configuration_path, .{}) catch |err| 104 std.debug.panic("failed to open configuration file {q}: {t}", .{ configuration_path, err }); 105 defer file.close(io); 106 break :configuration Configuration.loadFile(conf_arena, io, file) catch |err| 107 std.debug.panic("failed to load configuration file {q}: {t}", .{ configuration_path, err }); 108 }; 109 const c = &configuration; 110 111 var top_level_steps: std.array_hash_map.String(Configuration.Step.Index) = .empty; 112 defer top_level_steps.deinit(gpa); 113 114 for (c.steps, 0..) |*conf_step, step_index_usize| { 115 if (conf_step.owner != .root) continue; 116 const step_index: Configuration.Step.Index = @fromBackingInt(@intCast(step_index_usize)); 117 const flags = conf_step.flags(c); 118 if (flags.tag != .top_level) continue; 119 const name = step_index.ptr(c).name.slice(c); 120 try top_level_steps.putNoClobber(gpa, name, step_index); 121 } 122 123 std.debug.print("Steps:\n", .{}); 124 for (top_level_steps.keys()) |name| { 125 std.debug.print(" - {q}\n", .{name}); 126 } 127 std.debug.print( 128 \\Available Commands: 129 \\ - build [step names / step indices] 130 \\ - watch [step names / step indices] 131 \\ - exit 132 \\ 133 , .{}); 134 135 var stdin_reader_buffer: [256]u8 = undefined; 136 var stdin_reader = Io.File.stdin().reader(io, &stdin_reader_buffer); 137 const stdin = &stdin_reader.interface; 138 139 while (true) { 140 try Io.File.stdout().writeStreamingAll(io, "> "); 141 const command = try stdin.takeDelimiterExclusive('\n'); 142 stdin.toss(1); 143 if (std.mem.startsWith(u8, command, "build") or 144 std.mem.startsWith(u8, command, "watch")) 145 { 146 var steps: std.ArrayList(Configuration.Step.Index) = .empty; 147 defer steps.deinit(gpa); 148 149 const watch = std.mem.startsWith(u8, command, "watch"); 150 151 if (std.mem.cutPrefix(u8, command, "build ") orelse 152 std.mem.cutPrefix(u8, command, "watch ")) |command_args| 153 { 154 var it = std.mem.tokenizeScalar(u8, command_args, ' '); 155 while (it.next()) |arg| { 156 const step: Configuration.Step.Index = 157 if (std.fmt.parseInt(u32, arg, 10)) |i| 158 @fromBackingInt(i) 159 else |_| 160 top_level_steps.get(arg) orelse std.debug.panic("unexpected step name or index", .{}); 161 try steps.append(gpa, step); 162 } 163 } 164 165 if (steps.items.len < 1) { 166 try steps.append(gpa, c.default_step); 167 } 168 169 try client.serveBuildSteps(steps.items, .{ .watch = watch }); 170 171 while (true) { 172 const header: Server.Message.Header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { 173 error.Canceled, error.ConcurrencyUnavailable => |e| return e, 174 error.Timeout => unreachable, 175 else => |e| { 176 log.err("failed to receive message: {t}", .{err}); 177 break :blk e; 178 }, 179 }; 180 const body = client_stdout.take(header.bytes_len) catch unreachable; 181 log.debug("received {f} ({d} bytes)", .{ fmtEnum(header.tag), body.len }); 182 183 switch (header.tag) { 184 .bsp_build_started => {}, 185 .bsp_build_completed => if (!watch) break, 186 .bsp_step_started => {}, 187 .bsp_step_completed => {}, 188 .bsp_configuration => @panic("TODO"), 189 else => std.debug.panic("received unexpected message: {f}", .{fmtEnum(header.tag)}), 190 } 191 } 192 continue; 193 } else if (std.mem.eql(u8, command, "exit")) { 194 try client.serveBodylessMessage(.exit); 195 break; 196 } else { 197 log.err("unknown command: {q}", .{command}); 198 continue; 199 } 200 } 201 }; 202 203 try multi_reader.fillRemaining(.none); 204 205 if (client_stderr.bufferedLen() > 0) { 206 log.err("stderr:\n{s}\n", .{client_stderr.buffered()}); 207 } 208 209 try err; 210 211 const term = try child_process.wait(io); 212 213 if (!term.success()) { 214 log.err("maker {f}", .{term}); 215 } 216 } 217 218 const FormatEnum = union(enum) { 219 named: []const u8, 220 unnamed: usize, 221 222 pub fn format( 223 e: FormatEnum, 224 writer: *std.Io.Writer, 225 ) std.Io.Writer.Error!void { 226 switch (e) { 227 .named => |name| { 228 try writer.writeByte('.'); 229 try writer.writeAll(name); 230 }, 231 .unnamed => |number| try writer.print("0x{x}", .{number}), 232 } 233 } 234 }; 235 236 fn fmtEnum(e: anytype) FormatEnum { 237 if (std.enums.tagName(@TypeOf(e), e)) |name| { 238 return .{ .named = name }; 239 } else { 240 return .{ .unnamed = @backingInt(e) }; 241 } 242 } 243