Skip to content

Add missing documentation, break up large UI components, simplify/cleanup#11

Merged
dabrahams merged 15 commits intomainfrom
missing-doc-comments
Oct 11, 2025
Merged

Add missing documentation, break up large UI components, simplify/cleanup#11
dabrahams merged 15 commits intomainfrom
missing-doc-comments

Conversation

@dabrahams
Copy link
Copy Markdown

It's a large PR but mostly trivial transformations. The individual steps can easily be broken into separate PRs if that will help.

Copy link
Copy Markdown
Member

@camio camio left a comment

Choose a reason for hiding this comment

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

I left minor tweaks and suggestions, but it otherwise looks good to me. I especially like how the CLAUDE.md is developing.

Comment thread .vscode/settings.json.bak Outdated
);
file_menu
.append(&PredefinedMenuItem::separator())
.expect("Failed to append separator to File menu");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note the recommended message style documentation for .expect. The argument should describe the reason you think this should work okay.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

But I can't say that it should work okay; it's simply that the app is not in a viable environment for running if it's unable to build its menus. I have no idea why it might fail or whether it can plausibly happen, but any error is unrecoverable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You just stated the reason you think it should work okay. Put that in the expect clause and it reads better IMO:

Suggested change
.expect("Failed to append separator to File menu");
.expect("GUI subsystem operational");

You are saying you expect that the GUI subsystem is operational. That's all that needs to be said. There's no need to give additional context (e.g. that you happen to be adding a separator to the file menu).

Comment thread packages/mobile/src/main.rs Outdated

use ui::{ApplicationState, DocumentUI};

/// The application's top-level style.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You removed MAIN_CSS in Desktop's main.rs. Should the same not be done here?

Comment on lines +81 to +85
let window = window()
.ok_or_else(|| anyhow::anyhow!("Failed to get window object - browser API unavailable"))?;
let document = window
.document()
.ok_or_else(|| anyhow::anyhow!("Failed to get document object - browser API unavailable"))?;
.ok_or_else(|| anyhow!("Failed to get window object - browser API unavailable"))?;
let document = window.document().ok_or_else(|| {
anyhow!("Failed to get document object - browser API unavailable")
})?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
let window = window()
.ok_or_else(|| anyhow::anyhow!("Failed to get window object - browser API unavailable"))?;
let document = window
.document()
.ok_or_else(|| anyhow::anyhow!("Failed to get document object - browser API unavailable"))?;
.ok_or_else(|| anyhow!("Failed to get window object - browser API unavailable"))?;
let document = window.document().ok_or_else(|| {
anyhow!("Failed to get document object - browser API unavailable")
})?;
let window = window().context("Failed to get window object - browser API unavailable")?;
let document = window.document().context("Failed to get document object - browser API unavailable")?;

Copy link
Copy Markdown
Author

@dabrahams dabrahams Oct 11, 2025

Choose a reason for hiding this comment

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

.context doesn't work in these cases because they are Options, not Results, but these should use expect, so I'll fix that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The documentation for Context shows a trait implementation for Option. But, yeah, expect is the better choice here.

// Synthesize a link to the content and (programmatically) click it
let blob = Blob::new_with_str_sequence(&array)
.map_err(|_| anyhow::anyhow!("Failed to create Blob from content"))?;
.map_err(|_| anyhow!("Failed to create Blob from content"))?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
.map_err(|_| anyhow!("Failed to create Blob from content"))?;
.context("Failed to create Blob from content")?;

I'll stop making the suggestions. You get the idea.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Would be great if it worked. That Result type doesn't have a .context method. I'm adding this module in order to be able to do it. Whether it's a good idea, I dunno.

use anyhow::Result;

/// Anyhow's `context` and `with_context` methods for other result types.
trait AnyhowContext<T, E> {
    /// Returns `self`, adding `context` if `self` is an `Err`.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Returns `self`, adding the result of `makeContext()` if `self`
    /// is an `Err`.
    fn with_context<C, F>(self, makeContext: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

/// Anyhow's `context` and `with_context` methods for `std::Result`.
impl<T, E> AnyhowContext<T, E> for std::Result<T, E> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        anyhow!(self).context(context)
    }

    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        anyhow!(self).with_context(f)
    }
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Actually, it's QUITE a bit more complicated than that due to JSValue not being Error-conforming, nor Send/Sync. Try it yourself. I'm not doing this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

JSValue isn't Send/Sync for good reasons, but we can convert it into serde_json::Value which is. Something like this works:

#[derive(Debug)]
struct JsonEncodedError(serde_json::Value);

impl fmt::Display for JsonEncodedError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl std::error::Error for JsonEncodedError {}

impl From<JsValue> for JsonEncodedError {
    fn from(v: JsValue) -> Self {
        JsonEncodedError(
            serde_wasm_bindgen::from_value(v)
                .expect("JsValue to serde_json::Value conversion always succeeds"),
        )
    }
}

impl From<serde_json::Value> for JsonEncodedError {
    fn from(v: serde_json::Value) -> Self {
        JsonEncodedError(v)
    }
}

And then the user code would be something like this:

    let blob = Blob::new_with_str_sequence(&array)
        .map_err(Into::<JsonEncodedError>::into)
        .context("Failed to create Blob from content")?;

I think it would be a good idea to do this, otherwise we're swallowing potentially useful error information.

Comment on lines +141 to +142
let path = file_path(filename);
fs::remove_file(&path).with_context(|| format!("Failed to delete file '{filename}'"))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
let path = file_path(filename);
fs::remove_file(&path).with_context(|| format!("Failed to delete file '{filename}'"))
fs::remove_file(&file_path(filename)).with_context(|| format!("Failed to delete file '{filename}'"))

Comment on lines +147 to 148
let storage_dir = storage_directory();
let mut files = collect_json_files_from_dir(&storage_dir)?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
let storage_dir = storage_directory();
let mut files = collect_json_files_from_dir(&storage_dir)?;
let mut files = collect_json_files_from_dir(&storage_directory())?;

These one off variables are made in several places. Inlining them makes the code more concise without loss of clarity.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I loathe that pattern; blame the AI. I'll try to get rid of them.

Comment thread packages/ui/src/platform/file_operations.rs
Comment thread .dir-locals.el.bak Outdated
Comment thread packages/mobile/src/main.rs Outdated
use ui::{ApplicationState, DocumentUI};

/// The application's top-level style.
const MAIN_CSS: Asset = asset!("/assets/main.css");
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Suggested change
const MAIN_CSS: Asset = asset!("/assets/main.css");

@dabrahams dabrahams force-pushed the missing-doc-comments branch 2 times, most recently from 1fa85c6 to f15f1bb Compare October 11, 2025 03:53
@dabrahams dabrahams force-pushed the missing-doc-comments branch from f15f1bb to 7e5712e Compare October 11, 2025 03:56
@dabrahams dabrahams merged commit 3ed6a15 into main Oct 11, 2025
@dabrahams dabrahams deleted the missing-doc-comments branch October 11, 2025 03:57
@dabrahams dabrahams restored the missing-doc-comments branch October 13, 2025 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants