diff --git a/src/app_state.rs b/src/app_state.rs
index 9d12c93..6af1043 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -121,34 +121,9 @@ impl AppState {
             )?
             .target_directory;
 
-        // Build exercises from their metadata in the info file.
         let exercises = exercise_infos
             .into_iter()
-            .map(|mut exercise_info| {
-                // Leaking to be able to borrow in the watch mode `Table`.
-                // Leaking is not a problem because the `AppState` instance lives until
-                // the end of the program.
-                let path = exercise_info.path().leak();
-
-                exercise_info.name.shrink_to_fit();
-                let name = exercise_info.name.leak();
-                let dir = exercise_info.dir.map(|mut dir| {
-                    dir.shrink_to_fit();
-                    &*dir.leak()
-                });
-
-                let hint = exercise_info.hint.trim().to_owned();
-
-                Exercise {
-                    dir,
-                    name,
-                    path,
-                    test: exercise_info.test,
-                    strict_clippy: exercise_info.strict_clippy,
-                    hint,
-                    done: false,
-                }
-            })
+            .map(Exercise::from)
             .collect::<Vec<_>>();
 
         let mut slf = Self {
diff --git a/src/exercise.rs b/src/exercise.rs
index b62958b..37d33b7 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -10,6 +10,7 @@ use std::{
 use crate::{
     cmd::{run_cmd, CargoCmd},
     in_official_repo,
+    info_file::ExerciseInfo,
     terminal_link::TerminalFileLink,
     DEBUG_PROFILE,
 };
@@ -132,6 +133,34 @@ impl Exercise {
     }
 }
 
+impl From<ExerciseInfo> for Exercise {
+    fn from(mut exercise_info: ExerciseInfo) -> Self {
+        // Leaking to be able to borrow in the watch mode `Table`.
+        // Leaking is not a problem because the `AppState` instance lives until
+        // the end of the program.
+        let path = exercise_info.path().leak();
+
+        exercise_info.name.shrink_to_fit();
+        let name = exercise_info.name.leak();
+        let dir = exercise_info.dir.map(|mut dir| {
+            dir.shrink_to_fit();
+            &*dir.leak()
+        });
+
+        let hint = exercise_info.hint.trim().to_owned();
+
+        Exercise {
+            dir,
+            name,
+            path,
+            test: exercise_info.test,
+            strict_clippy: exercise_info.strict_clippy,
+            hint,
+            done: false,
+        }
+    }
+}
+
 impl Display for Exercise {
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         self.path.fmt(f)