``` title = "Type: A FOSS clone of typing.io" tags = ["misc"] date = "2016-10-08 17:29:42 -0400" old_permalink = ["/misc/2016/10/08/type/", "/misc/2016/type/", "/2016/type-a-foss-clone-of-typing-io/"] short_desc = "I made an awesome FOSS clone of typing.io that you can check out at type.shadowfacts.net." slug = "type" ``` **TL;DR**: I made an awesome FOSS clone of [typing.io](https://typing.io) that you can check out at [type.shadowfacts.net](https://type.shadowfacts.net) and the source of which you can see [here](https://github.com/shadowfacts/type). I've used [typing.io](https://typing.io) on and off for almost a year now, usually when I'm bored and have nothing else to do. Unfortunately, I recently completed the Java file, the C++ file, and the JavaScript file (that last one took too much time, jQuery has weird coding formatting standards, IMO) meaning I've completed pretty much everything that interests me. Now if you want to upload your own code to type, you have to pay $9.99 _a month_, which, frankly, is ridiculous. $10 a month to be able to upload code to a website only to have more than the 17 default files (one for each langauge) when I could build my own clone. This is my fourth attempt at building a clone of typing.io, and the first one that's actually been successful. (The first, second, and third all failed because I was trying to make a syntax highlighting engine work with too much custom code.) Type uses [CodeMirror](https://codemirror.net/), a fantastic (and very well documented) code editor which handles [syntax highlighting](#syntax-highlighting), [themes](#themes), [cursor handling](#cursor-handling), and [input](#input). ## Input Input was one of the first things I worked on. (I wanted to get the very basics working before I got cought up in minor details.) CodeMirorr's normal input method doesn't work for me, because in Type, all the text is in the editor beforehand and the user doesn't actually type it out. The CodeMirror instance is set to `readOnly` mode, making entering or removing text impossible. This is all well and good, but how can you practice typing if you can't type? Well, you don't actually type. The DOM `keypress` and `keydown` events are used to handle character input and handle special key input (return, backspace, tab, and escape) respectively. The `keypress` event handler simply moves the cursor one character and marks the typed character as completed. If the character the user typed isn't the character that's in the document they are typing, a CodeMirror [TextMarker](http://codemirror.net/doc/manual.html#markText) with the `invalid` class will be used to display a red error-highlight to the user. These marks are then stored in a 2-dimensional array which is used to check if the user has actully completed the file. The `keydown` event is used for handling special key pressed namely, return, backspace, delete, and escape. When handling a return press, the code first checks if the user has completed the current line (This is a little bit more complicated than checking if the cursor position is at the end of the line, because Type allows you to skip typing whitespace at the beggining and end of lines because every IDE/editor under the sun handles that for you). Then, the editor moves the cursor to the beggining of the next line (see the previous parenthetical). Backspace handling works much the same way, checking if the user is at the begging of the line, and if so, moving to the end of the previous line, or otherwise moving back 1 character. Delete also has a bit of extra functionality specific to Type. Whenever you press delete and the previous character was marked as invalid, the invalid marks needs to A) be cleared from the CodeMirror document and B) removed from the 2D array of invalid marks that's used for completion checking. The tab key requires special handling because it's not entered as a normal character and therefore special checking has to be done to see if the next character is a tab character. Type doesn't handling using the tab key with space-indentation like most editors/IDEs because most places where you'd encounter significant amounts of whitespace in the middle of a line, it's a tab character used to line up text across multiple lines. Escape is handled fairly simply. When escape is pressed and the editor is focused, a global `focus` variable is toggled, causing all other input-handling to be disabled, a **`Paused`** label is added/removed in the top right of the top bar, and lastly the `paused` class is toggled on the page, which, when active, gives the editor 50% opacity, giving it a nice effect that clearly indicates the paused state. ## Cursor Handling Preventing the cursor movement (something you obviously don't want for a typing practice thing) that's still possible, even in CodeMirror's read only mode, is accomplished simply by adding an event listener on the CodeMirror `mousedown` event and calling `preventDefault` on the event to prevent the editor's default behavior from taking place and calls the `focus` method on the editor instance, focusing it and un-pauses it if it was previously paused. ## Syntax Highlighting Syntax highlighting is handled completely using CodeMirror's [modes](http://codemirror.net/mode/index.html), so Type supports* everything that CodeMirror does. By default, Type will try to automatically detect a language mode to use based on the file's extension, falling back to plain-text if a mode can't be found. This is accomplished by searching the (ridiculously large and manually written) [langauges map](https://github.com/shadowfacts/type/blob/master/js/languages.js) that stores A) the JS CodeMirror mode file to load, B) the MIME type to pass to CodeMirror, and C) the extensions for that file-type (based on GitHub [linguis](https://github.com/github/linguist) data). Yes, I spent far too long manually writing that file when I probably could have [automated](https://xkcd.com/1319/) it. The script for the mode is then loaded using `jQuery.getScript`and the code, along with the MIME type, and a couple other things, are passed into `CodeMirror.fromTextArea`. \* Technically it does, however only a subset of those languages can actually be used because they seem common enough** to warrant being manually added to the languages map. ** I say "common" but [Brainfuck](https://github.com/shadowfacts/type/blob/master/js/languages.js#L2) and [FORTRAN](https://github.com/shadowfacts/type/blob/master/js/languages.js#L142) aren't really common, I just added them for shits and giggles. ## Themes Themes are handled fairly similarly to syntax highlighting. There's a massive `