diff --git a/README.md b/README.md
index 3e6d6c7c..15a1a8fd 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,16 @@ After the [initialization](#initialization), Rustlings can be launched by simply
 This will start the _watch mode_ which walks you through the exercises in a predefined order (what we think is best for newcomers).
 It will rerun the current exercise automatically every time you change the exercise's file in the `exercises/` directory.
 
+You can specify an editor command with the `--editor` option to open exercises directly from watch mode:
+
+```bash
+rustlings --editor code           # For VS Code
+rustlings --editor vim            # For Vim
+rustlings --editor "code --wait"  # For VS Code with wait argument
+```
+
+Then press `e` in watch mode to open the current exercise in your editor.
+
 <details>
 <summary><strong>If detecting file changes in the <code>exercises/</code> directory fails…</strong> (<em>click to expand</em>)</summary>
 
diff --git a/src/exercise.rs b/src/exercise.rs
index fdfbc4f6..ec77e96f 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -4,6 +4,7 @@ use crossterm::{
     style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
 };
 use std::io::{self, StdoutLock, Write};
+use std::process::Command;
 
 use crate::{
     cmd::CmdRunner,
@@ -79,6 +80,26 @@ impl Exercise {
 
         writer.write_str(self.path)
     }
+
+    /// Open the exercise file in the specified editor
+    pub fn open_in_editor(&self, editor: &str) -> io::Result<bool> {
+        let parts: Vec<&str> = editor.split_whitespace().collect();
+        if parts.is_empty() {
+            return Ok(false);
+        }
+
+        let mut cmd = Command::new(parts[0]);
+
+        // If the editor command has arguments, add them to the command
+        if parts.len() > 1 {
+            cmd.args(&parts[1..]);
+        }
+
+        cmd.arg(self.path);
+
+        let status = cmd.status()?;
+        Ok(status.success())
+    }
 }
 
 pub trait RunnableExercise {
diff --git a/src/main.rs b/src/main.rs
index 6688e3e6..221da27b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -35,6 +35,9 @@ struct Args {
     /// Only use this if Rustlings fails to detect exercise file changes.
     #[arg(long)]
     manual_run: bool,
+    /// Command to open exercise files in an editor (e.g. "code" for VS Code)
+    #[arg(long)]
+    editor: Option<String>,
 }
 
 #[derive(Subcommand)]
@@ -135,7 +138,11 @@ fn main() -> Result<ExitCode> {
                 )
             };
 
-            watch::watch(&mut app_state, notify_exercise_names)?;
+            watch::watch(
+                &mut app_state,
+                notify_exercise_names,
+                args.editor.as_deref(),
+            )?;
         }
         Some(Subcommands::Run { name }) => {
             if let Some(name) = name {
diff --git a/src/watch.rs b/src/watch.rs
index 3a56b4b6..ad4a10f7 100644
--- a/src/watch.rs
+++ b/src/watch.rs
@@ -62,6 +62,7 @@ enum WatchExit {
 fn run_watch(
     app_state: &mut AppState,
     notify_exercise_names: Option<&'static [&'static [u8]]>,
+    editor: Option<&str>,
 ) -> Result<WatchExit> {
     let (watch_event_sender, watch_event_receiver) = channel();
 
@@ -113,6 +114,9 @@ fn run_watch(
                 ExercisesProgress::CurrentPending => watch_state.render(&mut stdout)?,
             },
             WatchEvent::Input(InputEvent::Reset) => watch_state.reset_exercise(&mut stdout)?,
+            WatchEvent::Input(InputEvent::Edit) => {
+                watch_state.edit_exercise(&mut stdout, editor)?
+            }
             WatchEvent::Input(InputEvent::Quit) => {
                 stdout.write_all(QUIT_MSG)?;
                 break;
@@ -136,9 +140,10 @@ fn run_watch(
 fn watch_list_loop(
     app_state: &mut AppState,
     notify_exercise_names: Option<&'static [&'static [u8]]>,
+    editor: Option<&str>,
 ) -> Result<()> {
     loop {
-        match run_watch(app_state, notify_exercise_names)? {
+        match run_watch(app_state, notify_exercise_names, editor)? {
             WatchExit::Shutdown => break Ok(()),
             // It is much easier to exit the watch mode, launch the list mode and then restart
             // the watch mode instead of trying to pause the watch threads and correct the
@@ -152,6 +157,7 @@ fn watch_list_loop(
 pub fn watch(
     app_state: &mut AppState,
     notify_exercise_names: Option<&'static [&'static [u8]]>,
+    editor: Option<&str>,
 ) -> Result<()> {
     #[cfg(not(windows))]
     {
@@ -163,7 +169,7 @@ pub fn watch(
             rustix::termios::LocalModes::ICANON | rustix::termios::LocalModes::ECHO;
         rustix::termios::tcsetattr(stdin_fd, rustix::termios::OptionalActions::Now, &termios)?;
 
-        let res = watch_list_loop(app_state, notify_exercise_names);
+        let res = watch_list_loop(app_state, notify_exercise_names, editor);
 
         termios.local_modes = original_local_modes;
         rustix::termios::tcsetattr(stdin_fd, rustix::termios::OptionalActions::Now, &termios)?;
@@ -172,7 +178,7 @@ pub fn watch(
     }
 
     #[cfg(windows)]
-    watch_list_loop(app_state, notify_exercise_names)
+    watch_list_loop(app_state, notify_exercise_names, editor)
 }
 
 const QUIT_MSG: &[u8] = b"
diff --git a/src/watch/state.rs b/src/watch/state.rs
index 2413becd..42e09245 100644
--- a/src/watch/state.rs
+++ b/src/watch/state.rs
@@ -200,6 +200,7 @@ impl<'a> WatchState<'a> {
         show_key(b'l', b":list / ")?;
         show_key(b'c', b":check all / ")?;
         show_key(b'x', b":reset / ")?;
+        show_key(b'e', b":edit / ")?;
         show_key(b'q', b":quit ? ")?;
 
         stdout.flush()
@@ -269,6 +270,24 @@ impl<'a> WatchState<'a> {
         Ok(())
     }
 
+    pub fn edit_exercise(
+        &mut self,
+        stdout: &mut StdoutLock,
+        editor: Option<&str>,
+    ) -> io::Result<()> {
+        if let Some(editor) = editor {
+            if let Err(e) = self.app_state.current_exercise().open_in_editor(editor) {
+                writeln!(stdout, "Failed to open editor: {}", e)?;
+            }
+        } else {
+            writeln!(
+                stdout,
+                "No editor command specified. Use --editor to specify an editor."
+            )?;
+        }
+        Ok(())
+    }
+
     pub fn check_all_exercises(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
         // Ignore any input until checking all exercises is done.
         let _input_pause_guard = InputPauseGuard::scoped_pause();
diff --git a/src/watch/terminal_event.rs b/src/watch/terminal_event.rs
index 2400a3df..183ff6fe 100644
--- a/src/watch/terminal_event.rs
+++ b/src/watch/terminal_event.rs
@@ -14,6 +14,7 @@ pub enum InputEvent {
     CheckAll,
     Reset,
     Quit,
+    Edit,
 }
 
 pub fn terminal_event_handler(
@@ -51,6 +52,7 @@ pub fn terminal_event_handler(
 
                         continue;
                     }
+                    KeyCode::Char('e') => InputEvent::Edit,
                     KeyCode::Char('q') => break WatchEvent::Input(InputEvent::Quit),
                     _ => continue,
                 };