1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
//! [![gitlab]](https://gitlab.com/otafablab/otarustlings) [![crates-io]](https://crates.io/crates/otarustlings) [![docs-rs]](https://docs.rs/otarustlings) [![homepage]](https://otafablab.gitlab.io/rust-lukiokurssi/)
//!
//! [gitlab]: https://img.shields.io/badge/gitlab-8da0cb?style=for-the-badge&labelColor=555555&logo=gitlab
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//! [homepage]: https://img.shields.io/badge/course-AF0973?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBmaWxsPSIjZjVmNWY1IiB4bWxuczp2PSJodHRwczovL3ZlY3RhLmlvL25hbm8iPjxwYXRoIGQ9Ik0yMjkuNDkgMjc3LjQxMmMtNC45NDYgMS43NzctNy4zNzcgNS4xODYtOS44OTEgMTAuMjcxYTEwLjc5OCAxNC4wNzcgMCAwIDAtLjQzMiAzLjczNiAxMC43OTggMTQuMDc3IDAgMCAwIDEwLjc5NyAxNC4wNzYgMTAuNzk4IDE0LjA3NyAwIDAgMCAxMC43OTktMTQuMDc2IDEwLjc5OCAxNC4wNzcgMCAwIDAtMTAuNzk5LTE0LjA3OCAxMC43OTggMTQuMDc3IDAgMCAwLS40NzUuMDd6bTgzLjc3Ni0uODUzbC0uMTI1LjAzMWMtMy4zNS45MTgtNS44NzggMi4yOTMtNy45OCA0LjI5MWExMC43OTggMTQuMDc3IDAgMCAwLTMuMDkgOS43MzQgMTAuNzk4IDE0LjA3NyAwIDAgMCAxMC43OTcgMTQuMDc4IDEwLjc5OCAxNC4wNzcgMCAwIDAgMTAuNzk5LTE0LjA3OCAxMC43OTggMTQuMDc3IDAgMCAwLTEwLjQtMTQuMDU3eiIvPjxwYXRoIGQ9Ik0xODkuMjEzIDE0OC45MzljLTMuMTgxLjA0NS01Ljc3IDIuNjE3LTYuNDkgMTAuMjE1LTEuNzgyIDE4Ljc5Ny0xLjQ2NCAyMS45NDQtMTYuMTM5IDE1LjQ2MXMtMTkuMzUtOS45OTYtMTguMzExIDkuMDE0LjEzIDE4LjY4Ny0xNS4zOTMgMTQuMjk5LTE5LjE2LTIuNTQ2LTEzLjg1NCAxNC40MzIgMS41MTcgMTguOTgyLTE1LjAzMSAxNi41MS0xMy43MDggNy41OTEtMTAuNjQ2IDEzLjk4OCA2LjI4NiAxMS40MTcgNC45MDYgMTYuOTgyLTEwLjQwMiA1LjUwNC0xOS41MzMgNi4xMTMtNi43NDMgNi41NzEtNy4yNCA5LjI4NyAxNC45OTYgMTMuNjMyIDEyLjI0OCAyMC41MTRjLTMuMjY3LS4wMy0yOS4wMTQtMjEuMjM0LTI3Ljc2Mi0yNS4zOTFzNi4wNjYtMS4wNzQgMTMuOTE4LTE2LjE2MiA4LjcwNS0yNC4wNTYgMy45OTQtNDEuODc1LTI4Ljc1NC0zMi4xODktMjguNzU0LTMyLjE4OS0zLjI1OCAzNi42ODEtMi4wODQgNTguNTY2Yy0xOS40NzktMTkuMDMyLTE4LjU5Mi01MS4zNDYtMTguNTkyLTUxLjM0NnMtMTEuODYgNi45NTUtMjAuNDc1IDE4LjY4MiAxLjczOCAzMy40NDEgMS43MzggMzMuNDQxYzExLjU5NCAxNy40MzYgMTcuNzc2IDIxLjU1MSAyOC44OTMgMjguNjY4IDUuNzA3IDE5LjExNSAyNC42MjIgMzQuODQ1IDM1LjM3OSA0Mi42MjctNi40NjYgNi43MDktMjIuNTM4IDE3LjIxNy0yMi4yNyAyNi42NDguMjY4IDkuNDEgNzguNDQ1IDgzLjM4MyA3OC40NDUgODMuMzgzczEuMDM2LTMuMjg3LTkuMDItMjEuNzI5Yy0xMC4wMTgtMTguMzcxLTI3LjQxMy0zNy40MDEtMzIuNzU4LTU1Ljg4NS0yLjMyMS04LjAyOCAzLjg0Mi0xMC44OTYgMy44NDItMTAuODk2czI5LjU5OSA0NC40NTMgNDcuMzI4IDYxYy0zLjAwMi0yMC4xMTUtMTkuNzYxLTM3Ljc4My0yNC4wOC01Mi42NjYgMzMuODQ4IDI0LjcxMiAxNDYuMTM5IDI4LjYzNiAxNjYuMTQzIDI5LjE0NmwuMDctLjA4NmMxLjQzNC0xLjcwOCAyLjkwNi0zLjM4NCA0LjQ1MS00Ljk5NCAxLjY4MS0xLjc3MyAzLjQtMy41MTggNS4xNjQtNS4yMTdzMy41NzQtMy4zNTIgNS40MzQtNC45NDNhMTAyLjA1IDEwMi4wNSAwIDAgMSA1Ljc0LTQuNTc0IDg1LjA3IDg1LjA3IDAgMCAxIDYuMDg2LTQuMTA1IDYyLjI4IDYyLjI4IDAgMCAxIDQuMjU2LTIuMzQ0IDQ0LjA2IDQ0LjA2IDAgMCAxIDQuNDcxLTEuOTQxYzEuNTIzLS41NTggMy4wNzYtMS4wMiA0LjY1OC0xLjM1czMuMTk0LS41MyA0LjgyOC0uNTY4YzEuNjgxLS4wMjggMy4zNjYuMDIyIDUuMDQxLjE3YTQwLjI1IDQwLjI1IDAgMCAxIDQuOTg0Ljc0OCAzNC4zMyAzNC4zMyAwIDAgMSA0LjY5MSAxLjM0YzEuNTI3LjU1NSAzLjAxOCAxLjIxMyA0LjQ2MyAxLjk1OWE0Mi42IDQyLjYgMCAwIDEgNC4xOTkgMi40ODYgNDYuODYgNDYuODYgMCAwIDEgMy45MDIgMi45MjggODYuOTkgODYuOTkgMCAwIDEgNC4zNDQgMy44NjFjMS40MDcgMS4zMzEgMi43NzYgMi43IDQuMTI5IDQuMDg4bDQuNTc2IDQuNzc1YzQuODMyLS44NyAxMy45ODEtMi43MzggMjEuMjAzLTQuMTQ1LTQuMzkxIDQuNjgzLTEwLjc4MyA4LjY1OC0xMC43ODMgOC42NTgtNS41MSAyLjA2Mi04LjQ1NSAyLjQ5Ni0xMS42NTIgMi42MTMtLjYxOC0xLjQ1OC0uOTYyLTMuNDk2LTIuMzI3LTYuMDk1YTMyLjMzIDMyLjMzIDAgMCAwLTUuOTYyLTcuOTE1Yy0xLjQxMS0xLjM2MS0yLjgyMS0yLjY1LTQuMjU0LTMuODUycy0yLjg5LTIuMzE1LTQuMzk2LTMuMzI2LTMuMDY0LTEuOTIyLTQuNjk3LTIuNzE1YTM0LjUzIDM0LjUzIDAgMCAwLTUuMTUyLTIuMDEyIDM2LjI1IDM2LjI1IDAgMCAwLTUuNzY4LTEuMjIzYy0yLjA0My0uMjY3LTQuMjE0LS4zODctNi41MzktLjM0NmEyMi43NiAyMi43NiAwIDAgMC0zLjUyNy4zNDhjLTEuMTg4LjIwOC0yLjM4NS41MDQtMy41ODYuODc3cy0yLjQwNy44MjMtMy42MTEgMS4zMzhhNDcuOTMgNDcuOTMgMCAwIDAtMy42MDQgMS43M2MtMi4zOTIgMS4yNjktNC43NTQgMi43NTItNy4wNDUgNC4zNjFzLTQuNTExIDMuMzQ0LTYuNjEzIDUuMTExLTQuMDg3IDMuNTY3LTUuOTEgNS4zMTFhMTQyLjEgMTQyLjEgMCAwIDAtNC45NDEgNC45NjljLTIuNTE1IDMuNTQxLTUuNzA1IDYuNjgtNy4yNDYgMTEuMjE5IDE2LjkwNi03LjMwNiAzOC41ODctMy41NTggNTcuMTg5IDIuOTIxLTI1LjAwOSAzMi4xNDQtNTcuMzQ0IDI3Ljg2MS01Ny4zNDQgMjcuODYxczEwLjc3IDI1LjI1NiA1MS45MDggMTEuMjMyYzIyLjU1Ny03LjY4OSAzMy44OS0yNC43NzcgNDEuMTk1LTMwLjg2NyAyMi4xODYtMTAuMTE4IDQzLjY5OS0yNi4wOTYgNTUuMzAxLTQ0LjY0MyA4LjE4Ny01LjY3MSA5LjctNC44MzkgMTcuMDEyLTEwLjg5Ni0yLjYyMSA5Ljk2Mi00LjQ5NyAxNC45NjItMTEuNTE4IDI5LjQ4OC03LjIwOCAxNC45MTQtMTMuNTM5IDMyLjUwNi0xMy41MzkgMzIuNTA2bDI2LjY2Ni0zNi43NThjMy45LTUuNjgxIDEyLjE2Mi0xOC4yNzcgMTUuMDgyLTI0LjE2MiA4Ljc5NiAyLjg2Mi0xLjQ4MiAyNi41MTktMTUuNTE0IDU5LjE5NS05Ljg4NCAyMy4wMTctNy40OTQgMjguNTc0LTcuNDk0IDI4LjU3NGw0OC45MjYtNzAuOTg0YzEzLjA2Ni0yMC41MDEgMTcuNDE5LTE4Ljk0Ni04LjMwOS0zNy4xNTItMjUuNjYyLTE4LjE2MS0yNS42NzgtMTUuNzc0LTE4Ljc0OC0yNS4zMzQgNC41ODYtNi4zMjYgMjAuNzEzLTIxLjMyMi0zLjIwNS0yMy4wMzktMjMuMDc1LTEuNjU3LTE0Ljc3OC0xMC43NTMtMTAuMzk4LTE4Ljc4NSA3Ljg1Ny0xNC40MTEgMi43OTQtMTYuNDE3LS45ODYtMTcuMTE5LTMuODA5LS43MDctMTIuMzM5LS41NS0yMC45NjEuNDcxbC0xMi45NjkgMTA3LjM1Mi0zMi42NDEgNi40OTYgMTguMTQxLTE0NS4wMzktMi4wMDguMTAyLTMuNjk1LjY4NmMtMS4zNDguMjQ4LTIuNjkuNDc2LTMuODU0Ljc3My0yMy4xMTUgMy4wODItNDYuMTg5IDcuNjUtNjkuMzIyIDEwLjU5Mi0yLjI3OS4yNTEtNC41NS41OC02LjgyNC44NzlzLTQuNTUyLjU2OC02Ljg0NC42OTdjLTEuOTc1LjEtMy45NjQuMTA5LTUuOTQ5LjAxYTUxLjMzIDUxLjMzIDAgMCAxLTUuOTI0LS42MzNjLTEuOTU4LS4zMjgtMy44OTItLjc4LTUuNzg1LTEuMzY3cy0zLjc0NS0xLjMxLTUuNTM1LTIuMTg2bC00MC40NDEtMjAuNjkxLTQwLjM0LTIwLjg5NiAyLjQ4OC0xMS4zMTRjLTMuMjcxLTIuODAzLTcuNjM3LTUuOTk4LTExLjI0Mi01Ljk0N3ptMTMxLjYyMSAxMjYuNTc4YzQuMjMxLjA4OCA4LjM4NSAxLjQ4NCAxMi40MiA1LjAyOSA2LjQ1NSA1LjY3MiA4LjkxMiAxMi43MDYgOS4zOTEgMjIuMzAxcy0xLjkyMiAxNi41NTctOC44NDQgMjAuNjUtMTYuMDEgNy4xNjEtMjMuMjExIDMuOTE4LTEwLjk3LTguOTc0LTEyLjczLTE0LjQ5OC0xLjc0LTE2LjEyNiAxLjYwNy0yMy4zNzljMS43MjEtMy43MyAzLjQ2OC02LjU0NCA1LjY5My04LjY1OCAyLjAxNS0yLjc0MyA0Ljc5NC00LjMwOSA3LjcwNy00LjM0MmE4LjE2IDguMTYgMCAwIDEgLjM5OC4wMTljMi41NDQtLjY4OCA1LjA3LTEuMDkzIDcuNTY4LTEuMDQxem0tODEuNTI3LjE2OGM0LjkwNi0uMTAzIDkuOTU5IDEuMDM5IDEzLjk5NCA0LjU4NCA2LjQ1NSA1LjY3MiA5LjE1IDEzLjIyNyAxMC4xMDcgMjMuMDk2cy0yLjc3OSAxNy4wOTctOC42OTMgMjIuMDU5LTEzLjk1OCA2LjMyNy0yMi41NzQgMy42Ny0xNC44ODItMTEuMjk4LTE2LjY0My0xNi44MjItLjY0LTE0LjQxMSAyLjcwNy0yMS42NjRsMS4zOTUtMi45MjRjMS4yNTQtNS44NDYgNS4yNC05Ljk4NSA5Ljg5MS0xMC4yNzEuNDQ2LS4xNi45MDctLjMxMSAxLjM5Ni0uNDQ1IDIuNTg2LS43MDggNS40NzYtMS4yMTkgOC40Mi0xLjI4MXpNMzIxLjA3IDY4LjZjLTY3LjQzLjQ1OC0xMzcuNTQ0LjExNS0yMTIuOTkgMy41OTIgMzcuMTU1IDE5LjkyIDgyLjU3MiAzNC4yNTQgMTA5Ljc4MyA0Ny40My03LjA4NiAxMi42NzgtMTAuNTkyIDI0Ljc4OC0xNC43OTEgMzcuNTlsLS42NzYtLjYwNC0xLjg0IDguMzgxIDM5LjEzOSAyMC4yNzMgMzkuMjI3IDIwLjA5YzEuNjM1LjgyNSAzLjMyNCAxLjU1IDUuMDUzIDIuMTQ2czMuNTAxIDEuMDY1IDUuMzA3IDEuMzgzYTQ2LjMxIDQ2LjMxIDAgMCAwIDQuNzMuNjg0YzEuNTg2LjE0OCAzLjE4LjIxNiA0Ljc3My4yMTdzMy4xODgtLjA2NyA0Ljc3Ny0uMTk3IDMuMTczLS4zMjIgNC43NDYtLjU2NmwzMi44OTMtNC43NSAzMi44NC01LjExM2MzLjc1LS41ODIgNy40NDktMS4zNzEgMTEuMTY0LTIuMDg4IDEuODU3LS4zNTggMy43MTktLjY5OSA1LjU5NC0uOTg2Ljg2Ni0uMTMzIDEuNzQ3LS4yIDIuNjE5LS4zMDctLjU3My0yMy4wMDEtMi43ODEtNTIuMTE3LTIuNzgxLTUyLjExN2wxMy42MDItLjU2OC0yNS4yMjMgMTk3LjM0NCAyNy45MzgtNS41NTkgMjIuNjc2LTE5NC42NjRjMTYuMDg0LS43NDggNjkuNTQ3LTQuMTE5IDgyLjMwNy02LjkzOS01NS40NTMtMjAuNTg5LTEyNS42NzItNDIuODExLTE5MC44NjUtNjQuNjd6Ii8+PC9zdmc+
//! `otarustlings` exercise platform. Clone of
//! [rustlings](https://github.com/rust-lang/rustlings).
//!
//! The point of `otarustlings` is to learn Rust with hands on exercises and
//! small projects.
//!
//! # Updating & Installation
//!
//! To install or update otarustlings, use:
//!
//! ```console
//! cargo install --force otarustlings
//! ```
//!
//! # How to
//!
//! First, initialize the exercises:
//!
//! ```console
//! otarustlings init
//! ```
//!
//! > This creates the folder `exercises` with the latest exercises within.
//!
//! Next, start testing the exercise you wish to solve:
//!
//! ```console
//! otarustlings start
//! ```
//!
//! > You can also start a specific exercise with:
//! >
//! > ```console
//! > otarustlings start week4
//! > ```
//!
//! Finally, open the exercise in your favorite text editor, i.e. Emacs, and
//! solve the exercise in the way which feels natural.
//!
//! Once the exercise is compiles and passes the tests, it is marked with a
//! check mark `✓` in the menu. With `ENTER` you can select the next exercise
//! directly.
//!
//! # How to solve the exercises
//!
//! The semantics of the exercises are usually written as comments. If you see a
//! `_` in an invalid position, you need to replace it with something else. If
//! you see a `// TODO` or `todo!()` you are supposed to do what's called
//! _programming_, or _coding_, at the comment.
//!
//! Crate-like exercises, which are inside a folder, may have some additional
//! files which you need to read or to modify in order to solve the exercise.
//!
//! Don't be afraid to search for solutions online. No real programmer could do
//! their work without the internet and a search engine.
//!
//! # Subcommands
//!
//! ## `init`
//!
//! To create the initial exercise directory structure and write the exercises,
//! use:
//!
//! ```console
//! otarustlings init
//! ```
//!
//! The command creates a directory called `exercises` in the current directory.
//!
//! > Note: `init` does not overwrite old exercises.
//!
//! ## `start`
//!
//! To start testing your changes, use:
//!
//! ```console
//! otarustlings start
//! ```
//!
//! The command must be issued in the parent directory of `exercises`, i.e. the
//! same directory [`init`](#init) was called in.
//!
//! The first thing that is shown is a menu of the exercises. Using up and down
//! arrows, one can change the selection and pressing enter will start testing
//! it.
//!
//! All changes to the file are monitored and tested. The test output is shown
//! in the terminal.
//!
//! To return to menu, press `Q` or `ESC`.
//!
//! To quit `otarustlings`, press `Q` or `ESC` in the menu.
//!
//! > `CTRL-C` can also be used to exit `otarustlings`.
//!
//! ## `test`
//!
//! You can use `otarustlings` to directly test a particular exercise without
//! having to interact with it through the **terminal user interface**.
//!
//! ```console
//! otarustlings test week4/B5
//! ```
//!
//! > The same path qualifier works in [`start`](#start) too.
//!
//! ## `state`
//!
//! **NOTE:** Only modify **THE `state`** if necessary!
//!
//! To reset (remove) `exercises/state.toml` you can run:
//!
//! ```console
//! otarustlings state reset
//! ```
//!
//! # Development
//!
//! `otarustlings` is updated each week to add new exercises.
//!
//! Read the source code, star and fork the project and submit issues to [the
//! repository.](https://gitlab.com/otafablab/otarustlings)
use std::{path::PathBuf, sync::mpsc::Sender};
use crossterm::event::Event;
use state::Exercise;
use thiserror::Error;
pub mod exercise;
pub mod menu;
pub mod state;
pub mod tester;
pub mod utils;
/// Error which composes all the crate's errors together.
#[derive(Error, Debug)]
#[error("otarustlings error: {0:#}")]
pub enum Error {
/// A [`exercise::CompileError`].
CompileError(#[from] exercise::CompileError),
/// A [`exercise::RunError`].
RunError(#[from] exercise::RunError),
/// An [`notify::Error`]
NotifyError(#[from] notify::Error),
/// An unknown error.
#[error("unknown otarustlings error")]
Unknown,
}
/// Result with error being of type [`enum@Error`]
pub type Result<T> = std::result::Result<T, Error>;
/// Arguments that are passed to `rustc` to print in color
pub(crate) const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
/// A message from the notify and input threads to the compile thread
#[derive(Debug, Clone)]
pub enum Message {
Notify(PathBuf),
TestExercise,
SelectExercise(Exercise),
ExitExercise,
Terminate,
KeyEvent(Event, Sender<bool>),
Draw,
}