unneon/icie

Support for running and debugging using the vscode ui

thisHermit opened this issue · 6 comments

How do I use the vscode ui to debug the test cases?

If you hover the mouse over test case output, you will see two "replay" buttons. Right now, they only launch a terminal with a gdb or rr session, but I will try to look how to integrate it with VS Code gdb debugger UI when I will have the time.

I would be happy to work on it. I was imagining it was implemented. Btw, I was thinking to add a makefile to the initialisation too. I will keep you updated.

Great! I imagine checking out debug API docs and playing around with it would be a good place to start, but I've never looked into how it works. If the build system here or JS bindings give you any troubles (they are custom-made and pretty involved), feel free to ask me!

Actually, I have no experience with rust at all. But I managed find this

struct Action {
	onclick: &'static str,
	icon: &'static str,
	hint: &'static str,
}
const ACTION_COPY: Action = Action { onclick: "action_copy()", icon: "file_copy", hint: "Copy" };
const ACTION_EDIT: Action = Action { onclick: "action_edit()", icon: "edit", hint: "Edit" };
const ACTION_GDB: Action =
	Action { onclick: "action_gdb()", icon: "skip_previous", hint: "Debug in GDB" };
const ACTION_RR: Action =
	Action { onclick: "action_rr()", icon: "fast_rewind", hint: "Debug in RR" };
const ACTION_SET_ALT: Action =
	Action { onclick: "action_setalt()", icon: "check", hint: "Mark as correct" };
const ACTION_DEL_ALT: Action =
	Action { onclick: "action_delalt()", icon: "close", hint: "Unmark as correct" };

It looks like Action is using a javascript function in the onclick somehow,

Action { onclick: "action_gdb()", icon: "skip_previous", hint: "Debug in GDB" };

Is it calling the action_gdb function in src/test/view/script.js?

action_rr = make_action(ev => vscode.postMessage({ tag: "trigger_rr", in_path: ev.path_in }));
action_gdb = make_action(ev => vscode.postMessage({ tag: "trigger_gdb", in_path: ev.path_in }));
action_setalt = make_action(ev => vscode.postMessage({ tag: "set_alt", in_path: ev.path_in, out: ev.row.dataset['raw_out'] }));
action_delalt = make_action(ev => vscode.postMessage({ tag: "del_alt", in_path: ev.path_in }));
action_edit = make_action(ev => {
	let path = ev.path_in;
	if (ev.cell.classList.contains("desired")) {
		path = path.replace(/\.in$/, '.out');
	}
	vscode.postMessage({ tag: "edit", path: path });
});

On searching the project for trigger_gdb, I found this in src/test/view/manage.rs

Note::TriggerGDB { in_path } => {
	let source = source.clone();
	evscode::spawn(gdb(in_path, source));
},

In case this is correct, could you please give links to the architectural patterns involved here? I am curious to understand it before I add a Note and start going up the stack and start writing code. (if that really is the right way)

Please pardon me if all this is not at all related to the problem at hand.

Thanks in advance!

Is it calling the action_gdb function in src/test/view/script.js?

Yes. Adding new actions requires adding their metadata here, rendering them in the output cell here, sending them from JS here, specifying what information will be sent here and handling the clicks back in Rust here.

In case this is correct, could you please give links to the architectural patterns involved here?

Rust in render.rs creates HTML including all the outputs and buttons. The HTML includes script.js, which handles the button clicks, checks what was clicked and sends the information through a special VS Code API. Then, Rust in manage.rs receives this information and does the actual handling (spawning gdb, opening edit tabs, etc.).

Now, why is there so much going back and forth, and where to write the actual call-gdb-in-UI code? This has to be done that way because VS Code forces the button-handling code (webview) to run in a different process than the main extension for security reasons. Fortunately, after receiving the information we get the in_path (path to the test to debug) and can call the entire VS Code API however we like. So, as you guessed, your last snippet is the right place to write the actual logic.

In that snippet, evscode::spawn is called, so that the gdb spawning does not block other actions from being received. The gdb function is defined here, and as you can see it just launches the gdb process in a terminal. You will need to write a similar one (say, gdb_in_ui), which calls the VS Code APIs I linked earlier (or something else) instead of spawning a terminal.

So, for starters you can add the stuff I mentioned in the first paragraph, and for example display a Hello World when you receive a message to check that everything works. When you figure out how to work with the debugger UI, please tell me and I will help with adding the bindings to VS Code APIs (this is a little ugly). You may want to start an empty extension in JS to experiment with calling the debugger VS Code APIs, because experimenting in Rust without the bindings will be a bit of a pain :).

Just so you know, I created a Discord for developing ICIE. Feel free to join and ask me if you are stuck on something!