Crate editor_command

Source
Expand description

Get an executable Command to open a particular file in the user’s configured editor.

§Features

  • Load editor command from the VISUAL or EDITOR environment variables
  • Specify high-priority override and low-priority default commands to use
  • Pass one or more paths to be opened by the editor
  • Flexible builder pattern

§Examples

The simplest usage looks like this:

use editor_command::EditorBuilder;
use std::process::Command;

std::env::set_var("VISUAL", "vim");
let command: Command = EditorBuilder::edit_file("file.txt").unwrap();
assert_eq!(command.get_program(), "vim");

Here’s an example of using the builder pattern to provide both an override and a fallback command to EditorBuilder:

use editor_command::EditorBuilder;
use std::process::Command;

// In your app, this could be an optional field from a config object
let override_command = Some("code --wait");
let command: Command = EditorBuilder::new()
    // In this case, the override is always populated so it will always win.
    // In reality it would be an optional user-provided field.
    .source(override_command)
    .environment()
    // If both VISUAL and EDITOR are undefined, we'll fall back to this
    .source(Some("vi"))
    .build()
    .unwrap();
assert_eq!(format!("{command:?}"), "\"code\" \"--wait\"");

This pattern is useful for apps that have a way to configure an app-specific editor. For example, git has the core.editor config field.

§Tokio

EditorBuilder returns a std Command, which will execute synchronously. If you want to run your editor subprocess asynchronously via tokio, use the From<std::process::Command> impl on tokio::process::Command. For example:

let command: tokio::process::Command =
    EditorBuilder::edit_file("file.yaml").unwrap().into();

§Syntax

The syntax of the command is meant to resemble command syntax for common shells. The first word is the program name, and subsequent tokens (separated by spaces) are arguments to that program. Single and double quotes can be used to join multiple tokens together into a single argument.

Command parsing is handled by the crate [shell-words]. Refer to those docs for exact details on the syntax.

§Lifetimes

EditorBuilder accepts a lifetime parameter, which is bound to the string data it contains (both command strings and paths). This is to prevent unnecessary cloning when building commands/paths from &strs. If you need the instance of EditorBuilder to be 'static, e.g. so it can be returned from a function, you can simply use EditorBuilder<'static>. Internally, all strings are stored as Cows, so clones will be made as necessary.

use editor_command::EditorBuilder;

/// This is a contrived example of returning a command with owned data
fn get_editor_builder<'a>(command: &'a str) -> EditorBuilder<'static> {
    // The lifetime bounds enforce the .to_owned() call
    EditorBuilder::new().source(Some(command.to_owned()))
}

let command = get_editor_builder("vim").build().unwrap();
assert_eq!(command.get_program(), "vim");

§Resources

For more information on the VISUAL and EDITOR environment variables, check out this thread.

Structs§

EditorBuilder
A builder for a Command that will open the user’s configured editor. For simple cases you probably can just use EditorBuilder::edit_file. See crate-level documentation for more details and examples.

Enums§

EditorBuilderError
Any error that can occur while loading the editor command.