aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/bun/openInEditor.js23
-rw-r--r--src/javascript/jsc/api/bun.zig81
-rw-r--r--src/javascript/jsc/bindings/bindings.zig9
-rw-r--r--src/open.zig31
4 files changed, 131 insertions, 13 deletions
diff --git a/examples/bun/openInEditor.js b/examples/bun/openInEditor.js
new file mode 100644
index 000000000..59282c098
--- /dev/null
+++ b/examples/bun/openInEditor.js
@@ -0,0 +1,23 @@
+import { resolve } from "path";
+import { parse } from "querystring";
+
+export default {
+ fetch(req) {
+ if (req.url === "/favicon.ico")
+ return new Response("nooo dont open favicon in editor", { status: 404 });
+
+ var pathname = req.url.substring(1);
+ const q = pathname.indexOf("?");
+ var { editor } = parse(pathname.substring(q + 1)) || {};
+
+ if (q > 0) {
+ pathname = pathname.substring(0, q);
+ }
+
+ Bun.openInEditor(resolve(pathname), {
+ editor,
+ });
+
+ return new Response(`Opened ${req.url}`);
+ },
+};
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
index 6c3729f0d..f1a6e6c36 100644
--- a/src/javascript/jsc/api/bun.zig
+++ b/src/javascript/jsc/api/bun.zig
@@ -75,6 +75,7 @@ const URL = @import("../../../url.zig").URL;
const Transpiler = @import("./transpiler.zig");
const VirtualMachine = @import("../javascript.zig").VirtualMachine;
const IOTask = JSC.IOTask;
+
const is_bindgen = JSC.is_bindgen;
threadlocal var css_imports_list_strings: [512]ZigString = undefined;
@@ -540,6 +541,82 @@ pub fn getRouteNames(
return ref;
}
+const Editor = @import("../../../open.zig").Editor;
+pub fn openInEditor(
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSObjectRef,
+ args: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+) js.JSValueRef {
+ var edit = &VirtualMachine.vm.rareData().editor_context;
+
+ var arguments = JSC.Node.ArgumentsSlice.from(args);
+ var path: string = "";
+ var editor_choice: ?Editor = null;
+ var line: ?string = null;
+ var column: ?string = null;
+
+ if (arguments.nextEat()) |file_path_| {
+ path = file_path_.toSlice(ctx.ptr(), bun.default_allocator).slice();
+ }
+
+ if (arguments.nextEat()) |opts| {
+ if (!opts.isUndefinedOrNull()) {
+ if (opts.getTruthy(ctx.ptr(), "editor")) |editor_val| {
+ var sliced = editor_val.toSlice(ctx.ptr(), bun.default_allocator);
+ var prev_name = edit.name;
+
+ if (!strings.eqlLong(prev_name, sliced.slice(), true)) {
+ var prev = edit.*;
+ edit.name = sliced.slice();
+ edit.detectEditor(VirtualMachine.vm.bundler.env);
+ editor_choice = edit.editor;
+ if (editor_choice == null) {
+ edit.* = prev;
+ JSError(getAllocator(ctx), "Could not find editor \"{s}\"", .{sliced.slice()}, ctx, exception);
+ return js.JSValueMakeUndefined(ctx);
+ } else if (edit.name.ptr == edit.path.ptr) {
+ edit.name = bun.default_allocator.dupe(u8, edit.path) catch unreachable;
+ edit.path = edit.path;
+ }
+ }
+ }
+
+ if (opts.getTruthy(ctx.ptr(), "line")) |line_| {
+ line = line_.toSlice(ctx.ptr(), bun.default_allocator).slice();
+ }
+
+ if (opts.getTruthy(ctx.ptr(), "column")) |column_| {
+ column = column_.toSlice(ctx.ptr(), bun.default_allocator).slice();
+ }
+ }
+ }
+
+ const editor = editor_choice orelse edit.editor orelse brk: {
+ edit.autoDetectEditor(VirtualMachine.vm.bundler.env);
+ if (edit.editor == null) {
+ JSC.JSError(bun.default_allocator, "Failed to auto-detect editor", .{}, ctx, exception);
+ return null;
+ }
+
+ break :brk edit.editor.?;
+ };
+
+ if (path.len == 0) {
+ JSError(getAllocator(ctx), "No file path specified", .{}, ctx, exception);
+ return js.JSValueMakeUndefined(ctx);
+ }
+
+ editor.open(edit.path, path, line, column, bun.default_allocator) catch |err| {
+ JSC.JSError(bun.default_allocator, "Opening editor failed {s}", .{@errorName(err)}, ctx, exception);
+ return null;
+ };
+
+ return JSC.JSValue.jsUndefined().asObjectRef();
+}
+
pub fn readFileAsBytes(
_: void,
ctx: js.JSContextRef,
@@ -950,6 +1027,10 @@ pub const Class = NewClass(
.rfn = Bun.shrink,
.ts = d.ts{},
},
+ .openInEditor = .{
+ .rfn = Bun.openInEditor,
+ .ts = d.ts{},
+ },
.readAllStdinSync = .{
.rfn = Bun.readAllStdinSync,
.ts = d.ts{},
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 0ddd11862..05298ea27 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -2256,6 +2256,15 @@ pub const JSValue = enum(u64) {
return if (@enumToInt(value) != 0) value else return null;
}
+ pub fn getTruthy(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
+ if (get(this, global, property)) |prop| {
+ if (@enumToInt(prop) == 0 or prop.isUndefinedOrNull()) return null;
+ return prop;
+ }
+
+ return null;
+ }
+
/// Alias for getIfPropertyExists
pub const getIfPropertyExists = get;
diff --git a/src/open.zig b/src/open.zig
index f129dfc54..26b980a66 100644
--- a/src/open.zig
+++ b/src/open.zig
@@ -219,12 +219,14 @@ pub const Editor = enum(u8) {
file: []const u8,
line: ?string,
column: ?string,
- allocator: std.mem.Allocator,
+ _: std.mem.Allocator,
) !void {
- var file_path_buf: [bun.MAX_PATH_BYTES + 1024]u8 = undefined;
- var file_path_buf_stream = std.io.fixedBufferStream(&file_path_buf);
+ var spawned = try default_allocator.create(SpawnedEditorContext);
+ spawned.* = .{};
+ var file_path_buf_stream = std.io.fixedBufferStream(&spawned.file_path_buf);
var file_path_buf_writer = file_path_buf_stream.writer();
- var args_buf: [10]string = undefined;
+ var args_buf = &spawned.buf;
+ errdefer default_allocator.destroy(spawned);
var i: usize = 0;
@@ -309,19 +311,22 @@ pub const Editor = enum(u8) {
},
}
- var child_process = try std.ChildProcess.init(args_buf[0..i], allocator);
- child_process.stderr_behavior = .Pipe;
- child_process.stdin_behavior = .Ignore;
- child_process.stdout_behavior = .Pipe;
- try child_process.spawn();
- var thread = try std.Thread.spawn(.{}, autoClose, .{child_process});
+ spawned.child_process = try std.ChildProcess.init(args_buf[0..i], default_allocator);
+ var thread = try std.Thread.spawn(.{}, autoClose, .{spawned});
thread.detach();
}
+ const SpawnedEditorContext = struct {
+ file_path_buf: [1024 + bun.MAX_PATH_BYTES]u8 = undefined,
+ buf: [10]string = undefined,
+ child_process: *std.ChildProcess = undefined,
+ };
+
+ fn autoClose(spawned: *SpawnedEditorContext) void {
+ defer bun.default_allocator.destroy(spawned);
- fn autoClose(child_process: *std.ChildProcess) void {
Global.setThreadName("Open Editor");
- _ = child_process.wait() catch {};
- child_process.deinit();
+ spawned.child_process.spawn() catch return;
+ _ = spawned.child_process.wait() catch {};
}
};