Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): improved command matching with macros, fixes #1157 #1301

Merged
merged 27 commits into from
Feb 28, 2021

Conversation

nklayman
Copy link
Member

@nklayman nklayman commented Feb 26, 2021

What kind of change does this PR introduce? (check at least one)

  • Bugfix
  • Feature
  • New Binding Issue #___
  • Code style update
  • Refactor
  • Build-related changes
  • Other, please describe:

Does this PR introduce a breaking change? (check one)

  • Yes. Issue #___
  • No
  • Kinda

The PR fulfills these requirements:

  • When resolving a specific issue, it's referenced in the PR's title (e.g. fix: #xxx[,#xxx], where "xxx" is the issue number)
  • A change file is added if any packages will require a version bump due to this PR per the instructions in the readme.

If adding a new feature, the PR's description includes:

  • A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

Other information:

This PR adds two macros, #[command] and generate_handler![]. Combined, these allow command handling to look like this:

// Definition in main.rs

#[command]
fn reply_string(s: String) -> String {
  s
}
// Or, if the function needs the WebviewManager
#[command(with_manager)]
fn reply_string(manager: tauri::WebviewManager, s: String) -> String {
  println!("{}", manager.current_window_label());
  s
}

fn main() {
  tauri::AppBuilder::<Context>::new()
    .invoke_handler(generate_handler![reply_string])
    .build()
    .unwrap()
    .run();
}
// Calling from js
window.__TAURI__
  .invoke({
    cmd: 'reply_string',
    s: 'Hi'
  })
  .then((res) => console.log('Response:', res))

#[command] adds a second function, NAME_wrapper to function with name NAME. This wrapper function accepts the WebviewManager and serde_json::Value as args, and returns a tauri::InvokeResponse. The serde_json::Value should match the names and types of the original function args, ie the JSON for fn original(name: String) would be {"name": "some string"}. The wrapper function casts the value to a typed struct that contains all the function args, and passes them to the original function. It also passes the WebviewManager as the first arg if it is a with_webview command. It then converts the response from the original function to a tauri::InvokeResponse, and then returns it.

The generate_handler![] macro takes an array of paths to #[command] functions and returns a closure compatible with invoke_handler. This closure parses the arg string into a tauri::DispatchInstructions, a simple struct with two params: cmd, a string and args, a serde_json::Value. The cmd param is used in a generated match statement that matches it to one of the functions passed to this macro. It then calls that function's wrapper function with the WebviewManager and args, the JSON value that should hold all of that function's arguments. It returns the output from that function back to the webview.

TODO:

  • Clean up macro and use less .unwrap()
  • Have commands return a Result for better error handling
  • Improve error message from arg parse failure
  • Add support for functions that take the webview as an arg
  • Support for inferring webview arg type We decided to not include this
  • Support async functions
  • Update JS API to have cleaner syntax
  • Update init template to use macros
  • Update examples to use macros
  • (after merge) Type check the webview arg for with_webview commands
  • (after merge) Add support for state/context

Copy link
Member

@chippers chippers left a comment

Choose a reason for hiding this comment

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

we can use the root crate path to prevent any collisions with any in-scope items that clash (more likely for Result, but also possible for the crate names)

tauri-macros/src/command.rs Outdated Show resolved Hide resolved
tauri-macros/src/command.rs Outdated Show resolved Hide resolved
tauri-macros/src/command.rs Outdated Show resolved Hide resolved
tauri-macros/src/command.rs Outdated Show resolved Hide resolved
tauri-macros/src/command.rs Outdated Show resolved Hide resolved
tauri-macros/src/command.rs Outdated Show resolved Hide resolved
@nklayman nklayman marked this pull request as ready for review February 28, 2021 05:05
@nklayman nklayman requested a review from a team as a code owner February 28, 2021 05:05
@nklayman nklayman requested a review from a team February 28, 2021 05:05
@nklayman nklayman requested a review from a team February 28, 2021 05:05
@nklayman nklayman merged commit 1f2e7a3 into dev Feb 28, 2021
@nklayman nklayman deleted the feat/better-command-matching branch February 28, 2021 18:55
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.

None yet

3 participants