Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions tools/cargo-run/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod requirements;
pub enum Action {
Run,
Build,
Explore(Option<String>),
}

pub enum Target {
Expand Down Expand Up @@ -36,6 +37,7 @@ impl Task {
let (action, args) = match args.first() {
Some(&"build") => (Action::Build, &args[1..]),
Some(&"run") => (Action::Run, &args[1..]),
Some(&"explore") => (Action::Explore(args.get(1).map(|s| s.to_string())), &[] as &[&str]),
Some(&"help") => return None,
_ => (Action::Run, args),
};
Expand Down Expand Up @@ -74,6 +76,34 @@ pub fn npm_run_in_frontend_dir(args: &str) -> Result<(), Error> {
run_from(&format!("{npm} run {args}"), Some(&frontend_dir))
}

pub fn open_url(url: &str) -> Result<(), Error> {
#[cfg(target_os = "windows")]
let mut cmd = process::Command::new("cmd");
#[cfg(target_os = "windows")]
cmd.args(["/c", "start", url]);

#[cfg(target_os = "macos")]
let mut cmd = process::Command::new("open");
#[cfg(target_os = "macos")]
cmd.arg(url);

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
let mut cmd = process::Command::new("xdg-open");
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
cmd.arg(url);

let command_str = format!("{:?}", cmd);
let exit_code = cmd
.spawn()
.map_err(|e| Error::Io(e, format!("Failed to spawn command '{command_str}'")))?
.wait()
.map_err(|e| Error::Io(e, format!("Failed to wait for command '{command_str}'")))?;
if !exit_code.success() {
return Err(Error::Command(command_str, exit_code));
}
Ok(())
}
Comment on lines +79 to +105
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of open_url uses the run function, which splits the command string by whitespace. This is not robust for URLs, as they can contain special characters (like &) that are misinterpreted by the shell, or could in the future contain characters that cause incorrect splitting. A better approach is to construct the std::process::Command directly, passing the URL as a distinct argument. This ensures it's handled correctly across different platforms.

pub fn open_url(url: &str) -> Result<(), Error> {
	let status = {
		#[cfg(target_os = "windows")]
		{
			// The empty string argument is a workaround for `start` to correctly handle URLs with ampersands.
			process::Command::new("cmd").args(["/C", "start", "", url]).status()
		}
		#[cfg(target_os = "macos")]
		{
			process::Command::new("open").arg(url).status()
		}
		#[cfg(not(any(target_os = "windows", target_os = "macos")))]
		{
			process::Command::new("xdg-open").arg(url).status()
		}
	}
	.map_err(|e| Error::Io(e, format!("failed to run command to open url: {url}")))?;

	if !status.success() {
		return Err(Error::Command(format!("open url command for '{url}'"), status));
	}

	Ok(())
}


fn run_from(command: &str, dir: Option<&PathBuf>) -> Result<(), Error> {
let command = command.split_whitespace().collect::<Vec<_>>();
let mut cmd = process::Command::new(command[0]);
Expand Down
32 changes: 32 additions & 0 deletions tools/cargo-run/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fn usage() {
println!("<command>:");
println!(" [run] Run the selected target (default)");
println!(" build Build the selected target");
println!(" explore Open an assortment of tools for exploring the codebase");
println!(" help Show this message");
println!("<target>:");
println!(" [web] Web app (default)");
Expand Down Expand Up @@ -50,7 +51,35 @@ fn main() -> ExitCode {
ExitCode::SUCCESS
}

fn explore_usage() {
println!();
println!("USAGE:");
println!(" cargo run explore <tool>");
println!();
println!("OPTIONS:");
println!("<tool>:");
println!(" bisect Binary search through recent commits to find which introduced a bug or feature");
println!(" editor View an interactive outline of the editor's message system architecture");
println!();
}

fn run_task(task: &Task) -> Result<(), Error> {
if let Action::Explore(tool) = &task.action {
match tool.as_deref() {
Some("bisect") => return open_url("https://graphite.art/volunteer/guide/codebase-overview/debugging-tips/#build-bisect-tool"),
Some("editor") => return open_url("https://graphite.art/volunteer/guide/codebase-overview/editor-structure/#editor-outline"),
None | Some("--help") => {
explore_usage();
return Ok(());
}
Some(other) => {
eprintln!("Unknown explore tool: '{other}'");
explore_usage();
return Ok(());
}
}
}

requirements::check(task)?;

match (&task.action, &task.target, &task.profile) {
Expand All @@ -65,6 +94,7 @@ fn run_task(task: &Task) -> Result<(), Error> {
profile = match action {
Action::Run => &Profile::Debug,
Action::Build => &Profile::Release,
Action::Explore(_) => unreachable!(),
}
}

Expand Down Expand Up @@ -94,6 +124,8 @@ fn run_task(task: &Task) -> Result<(), Error> {

(Action::Build, Target::Cli, Profile::Debug) => run("cargo build -p graphene-cli")?,
(Action::Build, Target::Cli, Profile::Release | Profile::Default) => run("cargo build -r -p graphene-cli")?,

(Action::Explore(_), _, _) => unreachable!(),
}
Ok(())
}
2 changes: 1 addition & 1 deletion website/content/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Adam is a pragmatic problem solver with a talent for simplifying complexity. He
</section>

<section>
<div class="triptych">
<div class="triptych" id="extras">

<div class="block">

Expand Down
92 changes: 82 additions & 10 deletions website/content/volunteer/guide/codebase-overview/debugging-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,103 @@ title = "Debugging tips"

[extra]
order = 2 # Page number after chapter intro
css = ["/page/contributor-guide/bisect-tool.css"]
js = ["/js/page/contributor-guide/bisect-tool.js"]
+++

The Wasm-based editor has some unique limitations about how you are able to debug it. This page offers tips and best practices to get the most out of your problem-solving efforts.

## Comparing with deployed builds

When tracking down a bug, first check if the issue you are noticing also exists in `master` or just in your branch. Open up [dev.graphite.art](https://dev.graphite.art) which always deploys the lastest commit, as opposed to [editor.graphite.art](https://editor.graphite.art) which deploys the latest stable release. Build links for any commit may be found by clicking the "comment" icon on the right side of any commit in the [GitHub repo commits list](https://github.com/GraphiteEditor/Graphite/commits/master/).

Use *Help* > *About Graphite* in the editor to view any build's Git commit hash.

Beware of one potential pitfall: all deploys and build links are built with release optimizations enabled. This means some bugs (like crashes from bounds checks or debug assertions) may exist in `master` and would appear if run locally, but not in the deployed version.
When tracking down a bug, first check if the issue you are noticing also exists in `master` or just in your branch. Open up [dev.graphite.art](https://dev.graphite.art) which always deploys the lastest commit, as opposed to [editor.graphite.art](https://editor.graphite.art) which deploys the latest stable release. Build links for any commit may be found by clicking the "comment" icon on the right side of any commit in the GitHub repo [commits list](https://github.com/GraphiteEditor/Graphite/commits/master/).

Use *Help* > *About Graphite…* in the editor to view any build's Git commit hash.

Beware of a potential pitfall: all deploys and build links are built with release optimizations enabled. This means some bugs (like crashes from bounds checks or debug assertions) may exist in `master` and would appear if run locally, but not in the deployed version.

## Build bisect tool

```sh
# Access this quickly in the future:
cargo run explore bisect
```

This interactive tool helps you binary search through recent commits, test the build links of each, and pinpoint which change introduced a regression or added a feature.

<div class="bisect-tool">

<div class="phase active" data-phase="setup">
<div class="setup-section">
<div class="section-label">
<span><strong>What are you looking for?</strong></span>
</div>
<label>
<input type="radio" name="bisect-mode" value="regression" checked />
<span>Find when a regression or bug started</span>
</label>
<label>
<input type="radio" name="bisect-mode" value="feature" />
<span>Find when a feature was added or fixed</span>
</label>
</div>
<div class="setup-section">
<div class="section-label">
<span><strong>When do you estimate this changed?</strong></span>
</div>
<label>
<input type="radio" name="start-method" value="date" checked />
<span>Date</span>
</label>
<label>
<input type="radio" name="start-method" value="hash" />
<span>Commit</span>
</label>
</div>
<div class="commit-inputs">
<div class="start-input" data-input="date">
<input type="date" data-commit-date />
</div>
<div class="start-input hidden" data-input="hash">
<input type="text" data-commit-hash placeholder="Commit hash" pattern="[0-9a-fA-F]{7,40}" />
</div>
<span class="button arrow" data-start-button>Begin bisect</span>
</div>
</div>

<div class="phase" data-phase="bisect">
<div class="block feature-box-narrow">
<div class="step-header">
<span class="step-label" data-step-label><strong>Bisect step 1</strong></span>
<span class="go-back hidden" data-go-back-button>(<a>go back</a>)</span>
</div>
<div class="progress-info" data-progress-info></div>
<div class="commit-info" data-commit-info></div>
<span class="button arrow" data-test-build-button>Test this build</span>
<span class="findings">After testing, what have you found?</span>
<div class="bisect-actions">
<span class="button" data-issue-present-button></span>
<span class="button" data-issue-absent-button></span>
</div>
</div>
</div>

<div class="error-message" data-message-box></div>

</div>

## Printing to the console

Use the browser console (<kbd>F12</kbd>) to check for warnings and errors. Use the Rust macro `debug!("The number is {}", some_number);` to print to the browser console. These statements should be for temporary debugging. Remove them before your code is reviewed. Print-based debugging is necessary because breakpoints are not supported in WebAssembly.
Use the browser console (<kbd>F12</kbd>) to check for warnings and errors. In Rust, use `log::debug!("The number is {some_number}");` to print to the browser console. These statements should be for temporary debugging. Remove them before your code is reviewed. Print-based debugging is necessary because breakpoints are not supported in WebAssembly.

Additional print statements are available that *should* be committed:

- `error!()` is for descriptive user-facing error messages arising from a bug
- `warn!()` is for non-critical problems that likely indicate a bug somewhere
- `trace!()` is for verbose logs of ordinary internal activity, hidden by default but viewable by activating *Help* > *Debug: Print Trace Logs*
- `log::error!()` is for descriptive user-facing error messages arising from a bug
- `log::warn!()` is for non-critical problems that likely indicate a bug somewhere
- `log::trace!()` is for verbose logs of ordinary internal activity, hidden by default but viewable by activating *Help* > *Debug: Print Trace Logs*

## Message system logs

To also view logs of the messages dispatched by the message system, activate *Help* > *Debug: Print Messages* > *Only Names*. Or use *Full Contents* for a more verbose view containing the actual data being passed. This is an invaluable window into the activity of the message flow and works well together with `debug!()` printouts for tracking down message-related defects.
To also view logs of the messages dispatched by the message system, activate *Help* > *Debug: Print Messages* > *Only Names*. Or use *Full Contents* for a more verbose view containing the actual data being passed. This is an invaluable window into the activity of the message flow and works well together with `log::debug!()` printouts for tracking down message-related defects.

## Node/layer and document IDs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ The dispatcher lives at the root of the editor hierarchy and acts as the owner o

## Editor outline

Click to explore the outline of the editor subsystem hierarchy which forms the structure of the editor's subsystems, state, and interactions. Bookmark this page to reference it later.
```sh
# Access this quickly in the future:
cargo run explore editor
```

Click to explore the outline of the editor subsystem hierarchy which forms the structure of the editor's subsystems, state, and interactions.

<div class="structure-outline">
<!-- replacements::hierarchical_message_system_tree() -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Please ensure Clippy is enabled. This should be set up automatically in VS Code.

## Naming

Please use descriptive variable/function/symbol names and keep abbreviations to a minimum. Prefer spelling out full words most of the time, so `gen_doc_fmt` should be written out as `generate_document_format` instead.
Please use descriptive variable/function/symbol names and keep abbreviations to a minimum. Prefer spelling out full words most of the time, such as `generate_document_format` instead of `gen_doc_fmt`.

This avoids the mental burden of expanding abbreviations into semantic meaning. Monitors are wide enough to display long variable/function names, so descriptive is better than cryptic.

Expand Down
4 changes: 4 additions & 0 deletions website/sass/page/about.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@
}
}
}

#extras .button {
margin-top: 0;
}
Loading
Loading