diff --git a/docs/06-advanced-techniques/31-the-secure-shell/index.mdx b/docs/06-advanced-techniques/31-the-secure-shell/index.mdx index 8a0027dc..a7e67f55 100644 --- a/docs/06-advanced-techniques/31-the-secure-shell/index.mdx +++ b/docs/06-advanced-techniques/31-the-secure-shell/index.mdx @@ -1,7 +1,7 @@ --- title: 'The Secure Shell' slug: '/part-6-advanced-techniques/the-secure-shell/' -chapterNumber: 33 +chapterNumber: 3 --- So far we have been using the shell to operate on our local machine. We can use _Secure Shell Protocol_, or _SSH_, to open a secure network connection to a remote machine and use the shell to work on that machine. diff --git a/docs/06-advanced-techniques/32-a-vim-crash-course/images/markdown-basic.png b/docs/06-advanced-techniques/32-a-vim-crash-course/images/markdown-basic.png new file mode 100644 index 00000000..7e7bd8c9 Binary files /dev/null and b/docs/06-advanced-techniques/32-a-vim-crash-course/images/markdown-basic.png differ diff --git a/docs/06-advanced-techniques/32-a-vim-crash-course/images/vim-cheatsheet.png b/docs/06-advanced-techniques/32-a-vim-crash-course/images/vim-cheatsheet.png new file mode 100644 index 00000000..b0173568 Binary files /dev/null and b/docs/06-advanced-techniques/32-a-vim-crash-course/images/vim-cheatsheet.png differ diff --git a/docs/06-advanced-techniques/32-a-vim-crash-course/index.mdx b/docs/06-advanced-techniques/32-a-vim-crash-course/index.mdx new file mode 100644 index 00000000..d1df8f5f --- /dev/null +++ b/docs/06-advanced-techniques/32-a-vim-crash-course/index.mdx @@ -0,0 +1,546 @@ +--- +title: 'A Vim Crash Course' +slug: '/part-6-advanced-techniques/a-vim-crash-course/' +chapterNumber: 32 +--- + +import CodeBlock from '@theme/CodeBlock'; +import Image from '@theme/IdealImage'; +import AnnotatedCommand from '@site/src/components/AnnotatedCommmand/AnnotatedCommand.tsx'; +import Caret from '@site/src/components/Caret/Caret.tsx'; + +In this chapter we're going to introduce the popular Terminal Editor _Vim_. A Terminal Editor is a text editor that you can open directly in your terminal, normally from the shell. Many users find these editors hard to use, and some of them have a reputation for being highly complex. + +In this chapter we'll see why we might want to use or at least become familiar with Vim, and show just a few features that might excite you enough to want to dive in and learn more! + +## What is a Terminal Editor + +A Terminal Editor is any text editor that is designed to run inside a terminal, often from a shell. This means it is designed to be used without a mouse, on a smaller screen, and on a system that might have no graphical user interface or windowing or desktop environment. + +Some of the most popular terminal editors you might have hard of are _GNU nano_, _Vim_ and _Emacs_. Let's take a look at why we might want to know how to use a terminal editor. + +## Why use a Terminal Editor? + +Many technologists will be familiar with Graphical Text Editors, such as [Visual Studio Code](https://code.visualstudio.com/), [Atom](https://atom.io/) and [Sublime](https://www.sublimetext.com/). Software engineers will likely be familiar with Integrated Development Environments such as [Visual Studio](https://visualstudio.microsoft.com/) or the JetBrains family of IDEs which include dedicated environments for many languages, such as [IntelliJ IDEA](https://www.jetbrains.com/idea/) for Java. + +So with such a selection of powerful and user-friendly text editing options available, why would you choose to use a Terminal Editor? + +There are many reason, but perhaps the most compelling one is that you will not always have a graphical environment available! If you are working on a remote server using the `ssh` tool as described in [Chapter 31 - The Secure Shell](../31-the-secure-shell/index.mdx), you will not have a desktop or windowed environment to run a graphical tool. The _only_ options available for you to edit text, code or scripts in such an environment are terminal editors - because the terminal is your only interface to the server. + +There are other times where you might not have easy access to a graphical environment - for example if you are editing a file in a Docker container. + +There are some other reasons that being able to use a terminal editor is powerful: + +**Maintaining flow** - if you are working in a shell already and need to edit text, being able to quickly do so without leaving the shell, and ideally without even having to touch the mouse, will allow you to maintain your 'flow' while you work. + +**Speed of editing** - editors such as Vim and Emacs allow you to be _incredibly_ efficient at editing text, once you get over the initial learning curve. Vim in particular is designed to try and keep your fingers on the home row of the keyboard as much as possible to make it possible to manipulate text very quickly. + +**Customisation** - terminal editors can be customised to suit your working style - you can then manage your customisations through dotfiles that you share across environments as described in [Chapter 26 - Managing Your Dotfiles](../../05-building-your-toolkit/26-managing-your-dotfiles). + +**Improving Efficiency in Graphical Editors and other tools** - if you learn how to use Vim or Emacs and find yourself able to edit text very efficiently using their idioms, then you can install plugins in your graphical editors or IDEs, allowing you to edit text using the same commands. There are even browser plugins that let you navigate webpages using Vim style movement commands. + +All in all I believe it is extremely useful to get to grips with at least the basics of Vim - you will be more efficient when working with remote machines, when quickly editing text from the shell, and might even find it replaces your other tools for many tasks. + +## Introducing Vim + +I have chosen Vim as it has the reputation for being the most complex of the terminal text editors to work with, but actually with an hour or two of practice you'll find that it is quite straightforward to use for simple tasks. With just a little knowledge you'll be effective - and as you invest more time in learning you'll become increasingly efficient. + +Vim is installed on most Linux distributions out of the box and is an extremely popular editor. But it has a style of editing, called _Modal Editing_ that can be a bit confusing at first. + +### What is Modal Editing? + +Vim is a _modal text editor_. This means that it runs in different 'modes' - and in each mode the keyboard has different functions. For example, when you are in _Command Mode_ the keyboard is used to enter sequences that manipulate text or move the cursor. In _Insert Mode_ your keyboard is used just like with a normal text editor - typing edits the text on the screen. + +### Modal Editing in Action + +First, we'll open Vim by running the `vi` command: + +``` +$ vi + +█ +~ +~ +~ +~ +~ VIM - Vi IMproved +~ +~ version 8.2.4314 +~ by Bram Moolenaar et al. +~ Modified by +~ Vim is open source and freely distributable +~ +~ Help poor children in Uganda! +~ type :help iccf for information +~ +~ type :q to exit +~ type :help or for on-line help +~ type :help version8 for version info +~ +~ +~ +~ +~ + 0,0-1 All +``` + +When Vim is started it either displays the file that it has been asked to open or if no file has been provided it shows the welcome message above. + +Vim starts in **Command Mode**. This means that the keys on the keyboard are not used to enter text - they are used to enter commands. One command that is going to be useful is the 'insert' command, which tells vim to enter **Insert Mode**, before the cursor. The position of the cursor in the code block above is shown with a full-block `█` symbol. + +Let's insert some text. Enter the characters in the first column of the table below - the output should match what is shown on the right: + +| Keystrokes | Output | +|--------------|---------------| +| i | | +| Hello Vim! | Hello Vim! | + +The `i` command tells Vim to enter **Insert Mode**. Insert mode is the mode that will be most familiar to you - when Vim is in insert mode your keystrokes enter text in the current file. When Vim is in insert mode it behaves more like a non-modal editor. We can enter some text as shown above. + +You might have noticed that when you entered insert mode Vim updated its status bar to show you what mode it is in: + +``` +Hello Vim!█ +~ +~ +~ +-- INSERT -- 1,11 All +``` + +Vim will show you what mode you are in on the status line at the bottom of the screen. Vim's default mode is 'Command Mode' - when Vim is in command mode the mode is not shown - it's what you assume Vim is in unless it tells you otherwise. + +To return to Command Mode, press Control and 'C', or 'Escape'. In Vim's documentation a 'chord', which is more than one key pressed at the same time, is shown in angled brackets, to differentiate it from a 'sequence' which is a set of keystrokes pressed one after the other. Control and C is written as `` in the documentation for Vim. We will use the same style to describe chords and sequences. + +Let's exit insert mode: + +| Keystrokes | Output | +|------------|--------------| +| <C-c> | Hello Vim! | + +You will notice that the `-- INSERT --` text in the status bar is no longer shown - meaning we are back in Command Mode. + +Let's exit Vim. When we are in Command Mode, the keystrokes when enter are used to manipulate text or move around. If we want to perform an administrative task, such as saving a file or calling another program, we use what is called an _Ex Command_. _Ex_ is short for 'execute'. When we press the colon `:` keystroke, we enter 'Ex Mode'. This mode is a bit like Insert Mode, but for writing commands: + +| Keystrokes | Output | +|------------|--------| +| : | : | +| q! | :q! | + +Keystrokes we enter after entering Ex mode will show in the status line, showing the text for the command we are building. At this point the status bar for Vim will look like this: + +``` +Hello Vim! +~ +~ +~ +:q!█ +``` + +Vim is showing us that our current command is `q!`. This command translates to 'quit without saving'. Press the Enter key to execute the command - Vim will now close. + +We have seen the basics of modal editing - showing Vim's Command Mode, Insert Mode and Ex Mode. We can also close Vim - which is famously a task that people who haven't used Vim before struggle with! Now let's start building our own Vim Cheatsheet - using Vim - to show more of what it can do! + +## Building a Vim Cheat Sheet + +We're going to build a Vim Cheatsheet - this will be a great way to show what Vim can do at the same time as documenting our learnings as we go along. You'll then be able to extend your personal Cheatsheet over time with the commands that you find useful. + +Let's start by creating a folder to keep the cheat sheet in and initialing an empty Git Repository in the folder so that we can track changes to the cheat sheet. If you need a reminder on how Git works, check [Chapter 27 - Controlling Changes with Git](../../05-building-your-toolkit/27-controlling-changes-with-git/index.md). + +First we'll create a new folder, move into it and then initialise an empty Git repository with the main branched named `main`: + +``` +$ mkdir ~/vim-cheatsheet` +$ cd ~/vim-cheatsheet +$ git init -b main +Initialized empty Git repository in /home/dwmkerr/vim-cheatsheet/.git/ +``` + +## Creating a File in Vim + +We now have a new repository ready to hold our cheatsheet. Let's open Vim and tell it that we want to work on a file named `cheatsheet.md`: + +``` +$ vi cheatsheet.md + +█ +~ +~ +"cheatsheet.md" [New] 0,0-1 All +``` + +The text we are editing in Vim is called a _buffer_. A buffer can be thought of as a view on a file - when we open a file we load the context into a buffer - it is this buffer that Vim shows. When we want to create a new file, we enter text in a new buffer and then save it when we are ready. + +Vim is showing us in the status line that we have a buffer named _cheatsheet.md_ and that this is a 'New' buffer - it has not been saved. + +The extension `md` at the end of the file is short for 'Markdown'. Markdown is a plain text format that is great for documentation. You write text as normal - you can also use some special characters such as Hash `#` to format things like headings, or dash `-` for bullets. Markdown will be rendered in a very reader-friendl way when we look at on things like GitHub. + +Let's enter insert mode, and create a title for our cheatsheet, then exit insert mode. + +| Keystrokes | Output | +|--------------------|---------------------| +| i | | +| # Vim Cheatsheet | # Vim Cheatsheet | +| <C-c> | # Vim Cheatsheet | + +Now let's use the `w` (_write_) ex-mode command to save the file. Enter `:w` - the Vim status line will to tell us it has written the buffer to disk: + +``` +# Vim Cheatsheet +~ +~ +~ +"cheatsheet.md" [New] 1L, 17B written 1,16 All +``` + +Exit Vim by entering `:q`. Let's add this new cheatsheet file to our repository: + +``` +$ git add cheatsheet.md +``` + +Let's tell our shell to use Vim as our text editor. We're going to use Vim to work with Git for the duration of this chapter. When you are more familiar with Vim, being able to to work with Git repositories and commands without leaving the shell and using Vim as the editor will start to feel extremely efficient: + +``` +$ export EDITOR=vi +$ git commit + +█ +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# Committer: dwmkerr +# +# On branch main +# +# Initial commit +# +# Changes to be committed: +# new file: cheatsheet.md +# +~ +~ +"~/vim-cheatsheet/.git/COMMIT_EDITMSG" 13L, 325B 1,0-1 All +``` + +Git has opened Vim to ask us to provide a commit message. Git has also provided some helpful information on the changes we are committing - it's told us that we have a new file called _cheatsheet.md_ in the commit. Let's use Vim to enter a commit message: + +| Keystrokes | Output | +|----------------------|-----------------------| +| i | | +| add the cheatsheet | add the cheatsheet | +| <C-c> | add the cheatsheet | + +Now type `:wq` to _write_ and _quit_ - Git will use the message we have provided for the commit: + +``` + 1 file changed, 1 insertion(+) + create mode 100644 cheatsheet.md +``` + +We've used Vim to create the initial cheatsheet file as well as to quickly set the Git commit message - all without leaving our shell! + +## Vim Motions and Movement Commands + +Vim commands that move the cursor are called 'Motions'. Understanding how motions work is essential to becoming effective at moving around Vim buffers. + +Let's open our cheatsheet in Vim: + +``` +$ vi cheatsheet.md +``` + +Now update the file so that it looks like the version below, this will give us some text to play with: + +```sh +# Vim Cheatsheet + +## Vim Motions + +Vim motions are commands used to move the cursor. +``` + +Now that we have this text, let's see some of the motion commands in action. + +The table below shows what I think are the most essential Vim motions: + +| Motion | Usage | Motion | Usage | +|--------|----------------------------|--------|----------------------------| +| `gg` | Go to beginning of buffer. | `h` | Go left. | +| `G` | Go to end of buffer. | `j` | Go down. | +| `0` | Go to beginning of line. | `k` | Go up. | +| `$` | Go to end of line. | `l` | Go right. | +| `w` | Go forwards one word. | `)` | Go forwards one sentence. | +| `b` | Go backwards one word. | `(` | Go backwards one sentence. | + + +Let's see a few of these motions in action. Make sure to use `` to exit Insert Mode and enter Command Mode before entering the keystrokes below: + +| Keystrokes | Output | +|----------------------|-----------------------| +| gg | ## Vim Motions

## Vim Motions
| +| l | ## Vim Motions

## Vim Motions
| +| h | ## Vim Motions

## Vim Motions
| +| j | ## Vim Motions

## Vim Motions
| +| k | ## Vim Motions

## Vim Motions
| + +The first motion is `gg` - go to the beginning of the buffer. + +The next four motions are `hjkl` - move left, down, up and right. Vim uses these keys as they are all next to each other and on the home row for the right hand. Although it takes a little getting used to, once you use `hjkl` instead of arrow keys to move around you'll wonder how you lived without them - being able to navigate without moving your right hand from the home row let's you navigate text incredibly quickly. + +We can use the `0` and `$` motions to go to the beginning and end of a line: + +| Keystrokes | Output | +|----------------------|-----------------------| +| 0 | ## Vim Motions | +| $ | ## Vim Motions | + +The `w` and `b` motions move backwards and forwards by one word: + +| Keystrokes | Output | +|----------------------|-----------------------| +| 0 | ## Vim Motions | +| w | ## Vim Motions | +| b | ## Vim Motions | + +## Vim Command Counts + +Many Vim commands can be provided with a 'count', which indicates how many times the command should be run. This makes motions far more flexible - instead of pressing `jjjjj` to move down five lines, we can just press `5j`. + +Let's see how the cursor moves when we add counts to motion commands: + +| Keystrokes | Output | +|-|-| +| gg | ## Vim Motions

## Vim Motions
| +| 4j | ## Vim Motions

## Vim Motions
| +| 3w | ## Vim Motions

## Vim Motions
| + +## Vim Text Insert Commands + +Now that we know how to move the cursor with the movement commands, we can move to where we want to insert text and use the `i` command to enter Insert Mode. However, Vim has a set of commands that enter Insert Mode in specific positions - and these can save us moving around unnecessarily! + +The most essential 'enter insert mode' commands are: + +| Command | Description | +|---------|---------------------------------------------| +| `i` | Insert at cursor. | +| `I` | Insert beginning of current line. | +| `a` | Append text after the cursor. | +| `A` | Append text at the end of the current line. | +| `o` | Open a new line below the position. | +| `O` | Open a new line above the current line. | + +These commands make it much faster to quickly enter Insert Mode just where you like. Let's see some of them in action: + +| Keystrokes | Output | +|-|-| +| gg | ## Vim Motions | +| o | # Vim Cheatsheet
| +| Hello<C-c> | # Vim Cheatsheet
Hello
| +| I | # Vim Cheatsheet
Hello
| +| Welcome and <C-c> | # Vim Cheatsheet
Welcome and Hello
| +| A | # Vim Cheatsheet
Welcome and Hello
| +| Vim!<C-c> | # Vim Cheatsheet
Welcome and Hello Vim!
| +| O<C-c> | # Vim Cheatsheet

Welcome and Hello Vim
| + +We use the `` chord to quickly go back into Command Mode when we have inserted text. This should start to become a habit as you use Vim - it is faster to enter small amounts of text, then go back to command mode and reposition the cursor, than to enter lots of text and use the arrow keys to move around in Insert Mode[^1]. + +Now that we have seen motions and text insert commands, let's look at some essential Vim operators. + +## Vim Operators + +A Vim operator is any command that can be applied to a range of text. We can combine _counts_, _motions_ and _operators_ to rapidly manipulate a specific part of the buffer. + +Some of the operators that are particularly useful are listed in the table below - we'll see them in action afterwards: + +| Operator | Description | +|----------|--------------------------------------------------------------| +| `c` | Change the range, i.e. delete the characters and move into insert mode at the beginning of the range. | +| `d` | Delete the range. | +| `y` | Yank the range - copy it to a register ready to paste later. | +| `g~` | Swap case. | +| `gu` | Make lowercase ('go lower'). | +| `gU` | Make uppercase ('go upper'). | +| `!` | Send through external program. | + +We can use operators with a motion to alter a range of text. Let's see some of the basic operators: + +| Keystrokes | Output | +|----------------------------------------------|--------------------------------------------------------| +| gg |
Welcome to Vim!
| +| w |
Welcome to Vim!
| +| c2w |
Welcome to  
| +| to Terminal Editing!<C-c> |
Welcome to Terminal Editing!
| +| gU0 |
WELCOME TO TERMINAL EDITING!
| + +Hopefully from these examples you are starting to get an idea of just how powerful modal editing is - you are able to express complex changes to text, ranges of text, and movements in the buffer with just a few keystrokes. + +These operators can also quickly be applied to the current line - just type them twice! + +| Operator | Description | +|----------|--------------------------------------------------------------| +| `cc` | Change current line, i.e. delete the line and move into insert mode at the beginning of the line. | +| `dd` | Delete the current line. | +| `yy` | Yank the current line - copy it to a register ready to paste later. | +| `g~~` | Swap case for the current line. | +| `guu` | Make lowercase ('go lower') for the current line. | +| `gUU` | Make uppercase ('go upper') for the current line. | + +## Search Motions and the 'In' and 'A' Operators + +Some of the most powerful motions are the ones that can be used to search for a specific character. These 'search' motions can be used to quickly select a range of characters for an operator to perform on. Let's see a few of the most essential search motions: + +| Motion | Description | +|----------------|-------------------------------------------------| +| `f{character}` | Find the next specified character. | +| `F{character}` | Find the previous specified character. | +| `t{character}` | 'To' the next specified character. | +| `T{character}` | 'To' the previous previous specified character. | + +Now let's see how these motions look in action, by quickly moving around a little bit of Python code: + +| keystrokes | output | +|----------------------------------------------|--------------------------------------------------------| +| f( | def search_for_word(word): | +| 2fd | def search_for_word(word): | +| t_ | def search_for_word(word): | +| t | def search_for_word(word): | + +Just like any motion, we can add a `{count}` to indicate how many times we want the motion to run. + +Two other powerful motions are 'in' and 'a' - these motions are special because they come after the operator. Let's change some text using these motions: + +| Keystrokes | output | +|----------------------------------------------|--------------------------------------------------------| +| f( | def search_for_word(word): | +| gUi) | def search_for_word(WORD): | +| guu | def search_for_word(word): | +| f(da( | def search_for_word: | + +When you have searched for a character, you can use the following keystrokes to find the next or previous result: + +| Motion | Description | +|----------------|-------------------------------------------------| +| `;` | Move to the next result for the search motion. | +| `,` | Move to the previous result for the search motion. | + +## The 'In' and 'A' Modifiers + +The 'in' and 'a' modifiers for an operator are particularly useful when you want to change the contents of something like brackets, parenthesis, braces and so on. If you use `ca)` for example, you are saying 'Change a Brackets' - the brackets are removed and you are put into insert mode at the position the brackets were in. In comparison, `ci{` changes 'in' braces, removing the text inside the braces, but keeping the braces themselves. + +If you use an open bracket or brace, a space is added before and after the text you insert, if you use a close bracket or brace, no spaces are used: + +| Keystrokes | Output | +|----------------------------------------------|--------------------------------------------------------| +| g( | def search_for_word(word): | +| ci) | def search_for_word(): | +| word = "default"<C-c> | def search_for_word(word = "default")): | +| ca" | def search_for_word(word = ): | +| 'sample'<C-c> | def search_for_word(word = 'sample'): | + +## Editing Commands in Vim + +We're going to update our cheatsheet with a few notes - at this stage you can add any notes that you think are the most relevant, here are the first few lines of what I have added: + +```markdown +# Vim Cheatsheet + +## Vim Motions + +Vim motions are commands used to move the cursor. Essential motions are: + +* `hjkl` - move the cursor left/down/up/right +* `w` - forward one word +* `b` - back one word +* `(` - back one sentence +* `)` - forwards one sentence +* `0` - beginning of line +* `$` - end of line +* `gg` - beginning of buffer +* `G` - end of buffer + +Motions can take a `{count}` - this indicates how many motions we want to make, such as `3w` to move forwards three words. +``` + +Before we continue we should note that there are three new Markdown syntax features we have used: + +1. The `##` characters, which indicate a sub-heading +2. The `*` character, which indicates an item in a bullet list (a dash `-` can also be used for this) +3. The backtick `` ` `` character, which can surround text to indicate that it is code and should be rendered as such + +These simple formatting features will make the cheatsheet look excellent when it is viewed on GitHub or in a suitable editor - here's how it looks on GitHub at the moment: + +Screenshot: Basic Markdown Rendered by GitHub + + +Let's look at another way we can use Vim in our day to day work. We'll enter a shell command that has a mistake, and quickly edit the command and fix the mistake in Vim. Let's add these changes to Git - and show one more way to use Vim. Enter the line of text below in the shell but don't press 'Enter' to execute it yet! + +``` +$ git commit -m 'added more detail on motions' +``` + +This command will commit the changes - but we haven't added any yet! Rather than fixing this by moving around the command line, let's just open the current shell command line in Vim. Press `^x^e` (Control X, Control E) - this is the shell command to open the current line in the editor: + + +git commit -m 'added more detail on motions'
+~
+~
+~
+"/tmp/bash-fc-5094983766" 1L, 45B 1,1 All
+
+ +Let's fix up the command with our new Vim skills: + +| Keystrokes | Output | +|----------------------------------------------|--------------------------------------------------------| +| i | git commit -m 'added more detail on motions' | +| git add . && <C-c> | git add . && git commit -m 'added more detail on motions' | +| :wq | (Vim closes and `git commit` completes) | + +Being able to rapidly edit the current shell command in Vim is a huge time saver. + +## Next Steps with Vim + +Vim is a huge topic - we've barely scratched the surface but I hope have focused on the features that you can use most immediately. As you use Vim more, I would recommend learning about the following features in order: + +1. The dot command +2. Visual mode +3. Yank and paste and registers +4. Search and replace +5. Customising Vim with the _~/.vimrc_ file +6. Macros + +There are a few resources that I would recommend. The first is `vimtutor` and the next are some excellent online resources and books. + +### Vimtutor + +Vim comes installed with a very useful `vimtutor` program. You can run this program to open Vim with a special file that describes the key functionality of Vim. + +Use this program regularly while you are learning Vim to see how familiar you are getting and refresh your skills! + +### Vimcasts + +The excellent website [Vimcasts](http://vimcasts.org/) by Drew Neil has some superb videos on how to use Vim - from the basics to some really advanced functionality. + +Drew Neil is an extremely skilled Vim user and does a superb job of making a complex subject easy to follow. + +### Practical Vim & Modern Vim + +If you are enjoying using Vim, Drew Neil's books "Practical Vim" and "Modern" Vim should be on your bookshelf! They are truly excellent and again, just like his Vimcasts, make a complex subject much more user friendly. + +### The Vim Shortcuts Wallpaper + +Something I found useful when learning Vim was to have a wallpaper with the most common shortcuts. There are a number available on the web if you search for "Vim Wallpaper" - the one I currently use is below: + +![Vim Cheatsheet Wallpaper](./images/vim-cheatsheet.png) + +Unfortunately I have not been able to find the name of the original author. I found this file at: + +https://wallha.com/wallpaper/vim-cheat-sheet-minimalism-linux-1250034 + +## Summary + +In this chapter we introduced the concept of the terminal editor. We looked at the essentials of Vim, Insert Mode, Command Mode, motions, operators and more. We also introduced some resources that will help with your learning journey. + +In the next chapter we'll look at another essential tool - the Terminal Multiplexer. + +[^1]: There is also another benefit to short commands - it makes them easier to repeat with the _Dot Command_ which is not covered in this chapter but something that you will learn about as you use Vim more. diff --git a/docs/zz-developer-guide/components.mdx b/docs/zz-developer-guide/components.mdx new file mode 100644 index 00000000..9f907d56 --- /dev/null +++ b/docs/zz-developer-guide/components.mdx @@ -0,0 +1,103 @@ +--- +title: Components +--- + +This page shows the custom components that are available for Effective Shell. These are primarily used to improve the reading experience for code samples. + +To add more components to this page, please check the `src/theme/ReactLiveScope/index.js` file, which has been swizzled as per the guide at [Docusaurus - Code Blocks - Interactive code editor](https://docusaurus.io/docs/markdown-features/code-blocks#interactive-code-editor). Each custom component you want to use must be included in this file. + +## AsciinemaPlayer + +The `AsciinemaPlayer` component is renders an [`asciinema`](https://asciinema.org/) recording. Note that the recording file must be available to be served to the browser, so it will normally live somewhere in the `static` folder. + +First, import the component: + +```jsx +import AsciinemaPlayer from '@site/src/components/AsciinemaPlayer/AsciinemaPlayer.tsc'; +``` + +Use the component as below: + +```jsx live + +``` + +The bulk of the properties that are exposed are directly from the [`asciinema-player`](https://github.com/asciinema/asciinema-player) component - this page has a more detailed description of many of the properties listed below. The following properties are exposed: + +| Property | Usage | +| ---------------- | --------------------------------------------------------------------------------- | +| `src` | The location of the cast file, must be available from the browser. | +| `style` | Any additional CSS styles to apply. | +| `cols` | The number of columns in the player's terminal. | +| `rows` | The number of rows in the player's terminal. | +| `autoPlay` | Set this option to `true` if playback should start automatically. | +| `preload` | Set this option to `true` if the recording should be preloaded on player's initialization. | +| `loop` | Set this option to either true or a number if playback should be looped. When set to a number (e.g. 3) then the recording will be re-played given number of times and stopped after that. | +| `startAt` | Start playback at a given time. | +| `speed` | Playback speed. The value of 2 means 2x faster. | +| `idleTimeLimit` | Limit terminal inactivity to a given number of seconds. | +| `theme` | Terminal color theme. | +| `poster` | Poster (a preview frame) to display until the playback is started. | +| `fit` | Controls the player's fitting (sizing) behaviour inside its container element. | +| `fontSize` | Size of the terminal font. | + +## AnnotatedCommand + +The `AnnotatedCommand` component is used to create a set of keystrokes, for example for Vim, with a small text annotation beneath. This is useful in Markdown tables showing how Vim commands work, as multiline text in tables is a bit fiddly to work with. + +First, import the component: + +```jsx +import AnnotatedCommand from '@site/src/components/AnnotatedCommand/AnnotatedCommand.tsc'; +``` + +Use the component as below: + +```jsx live +gg2cw +``` + +The following properties are exposed: + +| Property | Usage | +| ---------------- | --------------------------------------------------------------------------------- | +| `annotation` | The text to show beneath the command. | + +## Caret + +The `Caret` component is useful when showing Vim or Terminal samples where you need to indicate the position of the caret. It can show a block caret, which is the standard for an ASCII terminal, or a line caret, which can be used in things like iTerm to indicate Insert Mode for Vim. + +First, import the component: + +```jsx +import Caret from '@site/src/components/Caret/Caret.tsx'; +``` + +Use the component as below: + +```jsx live + + def search_for_word(word): + +``` + +The following properties are exposed: + +| Property | Usage | +| ---------------- | --------------------------------------------------------------------------------- | +| `caretStyle` | The style of the cursor, `block` by default, or `line` for an 'insert mode' cursor. | + +## Tips for Developing Components + +Check the following resources for useful tips on Component Development: + +- [Docusaurus - Styling and Layout](https://docusaurus.io/docs/styling-layout) +- [Docusaurus - Code Blocks - Interactive code editor](https://docusaurus.io/docs/markdown-features/code-blocks#interactive-code-editor) diff --git a/docs/zz-developer-guide/images-and-diagrams.mdx b/docs/zz-developer-guide/images-and-diagrams.mdx new file mode 100644 index 00000000..601b5136 --- /dev/null +++ b/docs/zz-developer-guide/images-and-diagrams.mdx @@ -0,0 +1,38 @@ +--- +title: Images and Diagrams +--- + +import Image from '@theme/IdealImage'; +import Drawio from '@theme/Drawio' + +## Images + +The [`@docusaurus/plugin-ideal-image`](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-ideal-image) is used to allow lazy loading and zoom of images. + +Use the `Image` tag as shown: + +```markdown +import Image from '@theme/IdealImage'; + +``` + +This will render an image as shown below: + + + +## Diagrams + +Render a Draw.io diagram like so: + +``` +import Drawio from '@theme/Drawio' +import asymmetricEncryption from '!!raw-loader!./images/asymmetric-encryption.drawio'; + + +``` + +This would render as below: + +import asymmetricEncryption from '!!raw-loader!./images/asymmetric-encryption.drawio'; + + diff --git a/docs/zz-developer-guide/images/asymmetric-encryption.drawio b/docs/zz-developer-guide/images/asymmetric-encryption.drawio new file mode 100644 index 00000000..d9cfe527 --- /dev/null +++ b/docs/zz-developer-guide/images/asymmetric-encryption.drawio @@ -0,0 +1 @@ +3VfbUtswEP2aPJKRrTikj+QC7RQGpulM26eOYiu2GtvryjKJ+fqubPmGk0A7gYHygnS02mjP2V1LAzqLdleSJcENeDwc2MTbDeh8YNuWRcb4TyN5iUzsSQn4UnjGqAGW4oEbkBg0Ex5PO4YKIFQi6YIuxDF3VQdjUsK2a7aGsPurCfN5D1i6LOyj34Sngiqu8Ydm4SMXfqCq+M7LhYhVxiaSNGAebFsQXQzoTAKochTtZjzU5FW8lPsuD6zWB5M8Vs/Z8EV+yleLW0c6V78p8ZQD/OeZieKehZkJ+E6Ke6b4wB6H6Ha6kjjy9egzz00gKq/YwZgSPYwBd9DpNhCKLxPmamyLCYFYoKIQZ5b2xdyNLyGLvdtMhSLmBveY3NziLqF0kpAhcRA0B+NS8d3BiK2aR0xADhFXEg9Jqg0jQ73JPWqNyvm2UXJiTIKWhhYxIDPJ49euG35xYCj+C7qdHoPcw3QzU5AqAB9iFi4adFoQxrVXgrPG5hogMQT+4krlpnZYpqBLO7Il8+9mfzH5UdDsVNP5rr04z82sPKs+4HH+MR7IpMuPxF1VLpM+V0fs6H49JQ+ZEvfdc5xcnHGvFpY89hBZxK7ME8X1+IanqW4Z+3S8Zivsfh3uWSj8GMcuUsYlAjqhBbaXC7MQCc8rZeapeGCrwp9mPwERqyJEZzpw5scqwvQ+s7npOG2lDqfjwfI5I0OLTGjp69kSGHd3+vitUqTdHbBep5gJjyWrD/HvKlo9FY18bfGwA2ADsEnd7Mi+7tatvCeaW6obWOx/LYqSNMA1X6suMgWlIOpiODtV07O7Tc+ummCr6dU27a43fqmmZ/cUweR3+yVUfUyyKLxwFbSrpaisO0iFEqCrZmUo7JWTgkeyQPmlmdXXA3IimsdOh2ZrD830NVmmPZbn/HDeZyuU4H9K+9HkraX9qCfIFFbvO+kd+40l/aTHcY/gFi1PEtv7WofaclpfW2cQaoXQLV0XfwfFSJWETf1isGuk5YGQCbksaqF6GJDiLpwGde1VyRHtfP26GgpIz4cCP/fpMAR3o+1Oc08edWSl1nlPVnvUl5W+lKzV46/9LDEd6/2/Shzyeq8SnDYPzPKG1TzT6eIP \ No newline at end of file diff --git a/docs/zz-developer-guide/images/markdown-basic.png b/docs/zz-developer-guide/images/markdown-basic.png new file mode 100644 index 00000000..7e7bd8c9 Binary files /dev/null and b/docs/zz-developer-guide/images/markdown-basic.png differ diff --git a/docs/zz-developer-guide/images/vim-cheatsheet.png b/docs/zz-developer-guide/images/vim-cheatsheet.png new file mode 100644 index 00000000..b0173568 Binary files /dev/null and b/docs/zz-developer-guide/images/vim-cheatsheet.png differ diff --git a/docusaurus.config.js b/docusaurus.config.js index a4d492c3..935ae139 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -55,6 +55,11 @@ const config = { require.resolve('react-mailchimp-email-signup-form/dist/esm/index.css'), require.resolve('asciinema-player/dist/bundle/asciinema-player.css'), ], + + // Add theming support for languages we use. + prism: { + additionalLanguages: [], + }, }, gtag: { trackingID: 'G-8HZFMZV9Z4', @@ -124,6 +129,16 @@ const config = { theme: lightCodeTheme, darkTheme: darkCodeTheme, }, + liveCodeBlock: { + /** + * The position of the live playground, above or under the editor + * Possible values: "top" | "bottom" + * We use 'top' as we are currently using this editor to preview + * components, and we want to show the rendered component before its + * code (see 'Developer Guide > Components'). + */ + playgroundPosition: 'top', + }, }), plugins: [ @@ -137,6 +152,17 @@ const config = { require.resolve('docusaurus-plugin-drawio'), {} ], + [ + require.resolve('@docusaurus/theme-live-codeblock'), + {} + ], + [ + require.resolve('@docusaurus/plugin-ideal-image'), + { + // Enable this plugin in dev so that we can test it. + disableInDev: false, + }, + ], ], }; diff --git a/package-lock.json b/package-lock.json index 305d2c56..d96e3047 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1529,6 +1529,18 @@ } } }, + "@docusaurus/lqip-loader": { + "version": "2.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@docusaurus/lqip-loader/-/lqip-loader-2.0.0-beta.18.tgz", + "integrity": "sha512-arMahmfqF956n3xg+UmLIAl2uRFucsSBw0aTk4OwcXNvbWu+btmbstMi2fxFjGCyTOqojnepKDzJZMmZ1Tji3A==", + "requires": { + "@docusaurus/logger": "2.0.0-beta.18", + "file-loader": "^6.2.0", + "lodash": "^4.17.21", + "sharp": "^0.30.3", + "tslib": "^2.3.1" + } + }, "@docusaurus/mdx-loader": { "version": "2.0.0-beta.18", "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.18.tgz", @@ -1654,6 +1666,23 @@ "tslib": "^2.3.1" } }, + "@docusaurus/plugin-ideal-image": { + "version": "2.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-2.0.0-beta.18.tgz", + "integrity": "sha512-ukX+oPE6xz7QB7faIOu8zyp5FbrGGBvgXykYBtIFSsqSjo3yH7nzzNW928c1BtY/Uhr4rwtkVf38WazxCJy2BQ==", + "requires": { + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/lqip-loader": "2.0.0-beta.18", + "@docusaurus/responsive-loader": "^1.7.0", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", + "@endiliey/react-ideal-image": "^0.0.11", + "react-waypoint": "^10.1.0", + "sharp": "^0.30.3", + "tslib": "^2.3.1", + "webpack": "^5.70.0" + } + }, "@docusaurus/plugin-sitemap": { "version": "2.0.0-beta.18", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.18.tgz", @@ -1695,6 +1724,14 @@ "prop-types": "^15.6.2" } }, + "@docusaurus/responsive-loader": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@docusaurus/responsive-loader/-/responsive-loader-1.7.0.tgz", + "integrity": "sha512-N0cWuVqTRXRvkBxeMQcy/OF2l7GN8rmni5EzR3HpwR+iU2ckYPnziceojcxvvxQ5NqZg1QfEW0tycQgHp+e+Nw==", + "requires": { + "loader-utils": "^2.0.0" + } + }, "@docusaurus/theme-classic": { "version": "2.0.0-beta.18", "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.18.tgz", @@ -1737,6 +1774,22 @@ "utility-types": "^3.10.0" } }, + "@docusaurus/theme-live-codeblock": { + "version": "2.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-live-codeblock/-/theme-live-codeblock-2.0.0-beta.18.tgz", + "integrity": "sha512-aKliLCmJtwygiXOVsGUh8V86oRVSfFTRK3oSWJkPEfY0d8AFmFw+RndQxPYlq0UE4UtJEu6aEgSn0hZXObebWA==", + "requires": { + "@docusaurus/core": "2.0.0-beta.18", + "@docusaurus/theme-common": "2.0.0-beta.18", + "@docusaurus/theme-translations": "2.0.0-beta.18", + "@docusaurus/utils-validation": "2.0.0-beta.18", + "@philpl/buble": "^0.19.7", + "clsx": "^1.1.1", + "fs-extra": "^10.0.1", + "react-live": "2.2.3", + "tslib": "^2.3.1" + } + }, "@docusaurus/theme-search-algolia": { "version": "2.0.0-beta.18", "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.18.tgz", @@ -1823,6 +1876,11 @@ "tslib": "^2.3.1" } }, + "@endiliey/react-ideal-image": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@endiliey/react-ideal-image/-/react-ideal-image-0.0.11.tgz", + "integrity": "sha512-QxMjt/Gvur/gLxSoCy7VIyGGGrGmDN+VHcXkN3R2ApoWX0EYUE+hMgPHSW/PV6VVebZ1Nd4t2UnGRBDihu16JQ==" + }, "@hapi/hoek": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", @@ -1952,6 +2010,68 @@ "fastq": "^1.6.0" } }, + "@philpl/buble": { + "version": "0.19.7", + "resolved": "https://registry.npmjs.org/@philpl/buble/-/buble-0.19.7.tgz", + "integrity": "sha512-wKTA2DxAGEW+QffRQvOhRQ0VBiYU2h2p8Yc1oBNlqSKws48/8faxqKNIuub0q4iuyTuLwtB8EkwiKwhlfV1PBA==", + "requires": { + "acorn": "^6.1.1", + "acorn-class-fields": "^0.2.1", + "acorn-dynamic-import": "^4.0.0", + "acorn-jsx": "^5.0.1", + "chalk": "^2.4.2", + "magic-string": "^0.25.2", + "minimist": "^1.2.0", + "os-homedir": "^1.0.1", + "regexpu-core": "^4.5.4" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "regenerate-unicode-properties": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regexpu-core": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + }, + "regjsparser": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, "@polka/url": { "version": "1.0.0-next.21", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", @@ -2376,9 +2496,9 @@ "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" }, "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/qs": { "version": "6.9.7", @@ -2391,9 +2511,9 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/react": { - "version": "17.0.43", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.43.tgz", - "integrity": "sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==", + "version": "17.0.44", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.44.tgz", + "integrity": "sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2640,11 +2760,26 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" }, + "acorn-class-fields": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.2.1.tgz", + "integrity": "sha512-US/kqTe0H8M4LN9izoL+eykVAitE68YMuYZ3sHn3i1fjniqR7oQ3SPvuMK/VT1kjOQHrx5Q88b90TtOKgAv2hQ==" + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" + }, "acorn-import-assertions": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" + }, "acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", @@ -2782,6 +2917,49 @@ "picomatch": "^2.0.4" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "arg": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", @@ -2964,6 +3142,11 @@ "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -2979,6 +3162,16 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -3128,6 +3321,15 @@ "picocolors": "^1.0.0" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3297,6 +3499,11 @@ "readdirp": "~3.6.0" } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -3376,11 +3583,40 @@ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, "collapse-white-space": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -3394,6 +3630,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "colord": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", @@ -3430,6 +3675,16 @@ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" }, + "component-props": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/component-props/-/component-props-1.1.1.tgz", + "integrity": "sha1-+bffm5kntubZfJvScqqGdnDzSUQ=" + }, + "component-xor": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/component-xor/-/component-xor-0.0.4.tgz", + "integrity": "sha1-xV2DzMG5TNUImk6T+niRxyY+Wao=" + }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -3495,6 +3750,16 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "consolidated-events": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/consolidated-events/-/consolidated-events-2.0.2.tgz", + "integrity": "sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ==" + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -3945,6 +4210,11 @@ "slash": "^3.0.0" } }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -3963,6 +4233,11 @@ "repeat-string": "^1.5.4" } }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, "detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -4038,6 +4313,15 @@ "utila": "~0.4" } }, + "dom-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dom-iterator/-/dom-iterator-1.0.0.tgz", + "integrity": "sha512-7dsMOQI07EMU98gQM8NSB3GsAiIeBYIPKpnxR3c9xOvdvBjChAcOM0iJ222I3p5xyiZO9e5oggkNaCusuTdYig==", + "requires": { + "component-props": "1.1.1", + "component-xor": "0.0.4" + } + }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -4286,6 +4570,11 @@ } } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "express": { "version": "4.17.3", "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", @@ -4669,6 +4958,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", @@ -4700,6 +4994,54 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -4728,6 +5070,11 @@ "pump": "^3.0.0" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, "github-slugger": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", @@ -4904,6 +5251,11 @@ "has-symbols": "^1.0.2" } }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -5181,6 +5533,11 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5781,6 +6138,14 @@ "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.9.0.tgz", "integrity": "sha512-Be5vFuc8NAheOIjviCRms3ZqFFBlzns3u9DXpPSZvALetgnydAN0poV71pVLFn0keYy/s4VblMMkqewTLe+KPg==" }, + "magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -6002,6 +6367,11 @@ "minimist": "^1.2.6" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "mrmime": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", @@ -6031,6 +6401,11 @@ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==" }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6050,6 +6425,19 @@ "tslib": "^2.0.3" } }, + "node-abi": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", + "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, "node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -6099,6 +6487,17 @@ "path-key": "^3.0.0" } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "nprogress": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", @@ -6112,6 +6511,11 @@ "boolbase": "^1.0.0" } }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -6191,6 +6595,11 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -6767,6 +7176,26 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.0.tgz", "integrity": "sha512-9MEURwzNMKpAil/t6+wabDIJI6oG6GnwypYxiJDvQnW+fHDTt51PYuLZ1QUM31hFr7sDaj9qTaShAF9VIxuxGQ==" }, + "prebuild-install": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", + "integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -7162,6 +7591,79 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-live": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-live/-/react-live-2.2.3.tgz", + "integrity": "sha512-tpKruvfytNETuzO3o1mrQUj180GVrq35IE8F5gH1NJVPt4szYCx83/dOSCOyjgRhhc3gQvl0pQ3k/CjOjwJkKQ==", + "requires": { + "buble": "0.19.6", + "core-js": "^2.4.1", + "dom-iterator": "^1.0.0", + "prism-react-renderer": "^1.0.1", + "prop-types": "^15.5.8", + "react-simple-code-editor": "^0.10.0", + "unescape": "^1.0.1" + }, + "dependencies": { + "buble": { + "version": "0.19.6", + "resolved": "https://registry.npmjs.org/buble/-/buble-0.19.6.tgz", + "integrity": "sha512-9kViM6nJA1Q548Jrd06x0geh+BG2ru2+RMDkIHHgJY/8AcyCs34lTHwra9BX7YdPrZXd5aarkpr/SY8bmPgPdg==", + "requires": { + "chalk": "^2.4.1", + "magic-string": "^0.25.1", + "minimist": "^1.2.0", + "os-homedir": "^1.0.1", + "regexpu-core": "^4.2.0", + "vlq": "^1.0.0" + } + }, + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "regenerate-unicode-properties": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regexpu-core": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + }, + "regjsparser": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, "react-loadable": { "version": "npm:@docusaurus/react-loadable@5.5.2", "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", @@ -7223,6 +7725,11 @@ "tiny-warning": "^1.0.0" } }, + "react-simple-code-editor": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.10.0.tgz", + "integrity": "sha512-bL5W5mAxSW6+cLwqqVWY47Silqgy2DKDTR4hDBrLrUqC5BXc29YVx17l2IZk5v36VcDEq1Bszu2oHm1qBwKqBA==" + }, "react-textarea-autosize": { "version": "8.3.3", "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz", @@ -7233,6 +7740,24 @@ "use-latest": "^1.0.0" } }, + "react-waypoint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-waypoint/-/react-waypoint-10.1.0.tgz", + "integrity": "sha512-wiVF0lTslVm27xHbnvUUADUrcDjrQxAp9lEYGExvcoEBScYbXu3Kt++pLrfj6CqOeeRAL4HcX8aANVLSn6bK0Q==", + "requires": { + "@babel/runtime": "^7.12.5", + "consolidated-events": "^1.1.0 || ^2.0.0", + "prop-types": "^15.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -7937,6 +8462,11 @@ "send": "0.17.2" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -7960,6 +8490,21 @@ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, + "sharp": { + "version": "0.30.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.3.tgz", + "integrity": "sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg==", + "requires": { + "color": "^4.2.1", + "detect-libc": "^2.0.1", + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1", + "semver": "^7.3.5", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7993,6 +8538,51 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "sirv": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", @@ -8075,6 +8665,11 @@ } } }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, "space-separated-tokens": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", @@ -8269,6 +8864,29 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, "terser": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", @@ -8384,6 +9002,14 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "type-fest": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.12.2.tgz", @@ -8416,6 +9042,14 @@ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==" }, + "unescape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", + "integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==", + "requires": { + "extend-shallow": "^2.0.1" + } + }, "unherit": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", @@ -8766,6 +9400,11 @@ "unist-util-stringify-position": "^2.0.0" } }, + "vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" + }, "wait-on": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", @@ -9150,6 +9789,26 @@ "isexe": "^2.0.0" } }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + }, + "dependencies": { + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, "widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", diff --git a/package.json b/package.json index 5b2339bd..9247ad25 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,12 @@ "@cmfcmf/docusaurus-search-local": "^0.10.0", "@docusaurus/core": "2.0.0-beta.18", "@docusaurus/module-type-aliases": "^2.0.0-beta.18", + "@docusaurus/plugin-ideal-image": "^2.0.0-beta.18", "@docusaurus/preset-classic": "2.0.0-beta.18", + "@docusaurus/theme-live-codeblock": "^2.0.0-beta.18", "@mdx-js/react": "^1.6.21", "@tsconfig/docusaurus": "^1.0.5", - "@types/react": "^17.0.43", + "@types/react": "^17.0.44", "asciinema-player": "^3.0.0-rc.1", "clsx": "^1.1.1", "docusaurus-plugin-drawio": "^0.1.7", diff --git a/sidebars.js b/sidebars.js index f68747d4..52a3c1e7 100644 --- a/sidebars.js +++ b/sidebars.js @@ -82,6 +82,7 @@ const sidebars = { 'advanced-techniques/understanding-shell-expansion/index', 'advanced-techniques/how-to-avoid-scripting/index', 'advanced-techniques/the-secure-shell/index', + 'advanced-techniques/a-vim-crash-course/index', 'advanced-techniques/master-the-multiplexer/index', ] }, @@ -92,6 +93,14 @@ const sidebars = { 'xx-appendices/thanks', ] }, + { + type: 'category', + label: 'Developer Guide', + items: [ + 'zz-developer-guide/components', + 'zz-developer-guide/images-and-diagrams', + ] + }, ], }; diff --git a/src/components/AnnotatedCommmand/AnnotatedCommand.tsx b/src/components/AnnotatedCommmand/AnnotatedCommand.tsx new file mode 100644 index 00000000..c2c74159 --- /dev/null +++ b/src/components/AnnotatedCommmand/AnnotatedCommand.tsx @@ -0,0 +1,32 @@ +// @ts-check + +import React from 'react'; + +type AnnotatedCommandProps = { + annotation: string; + style: React.CSSProperties; + children: JSX.Element; +}; + +const annotationStyle = { + color: '#333333', + fontStyle: 'italic', +}; + +const AnnotatedCommand: React.FC = ({ + annotation, + children, +}: AnnotatedCommandProps) => { + return ( +
+ {children} +
+
+ + {annotation} + +
+ ) +}; + +export default AnnotatedCommand; diff --git a/src/components/Caret/Caret.tsx b/src/components/Caret/Caret.tsx new file mode 100644 index 00000000..b0b57a1e --- /dev/null +++ b/src/components/Caret/Caret.tsx @@ -0,0 +1,42 @@ +// @ts-check +import React from 'react'; + +enum CaretStyle { + default = 'block', + block = 'block', + line = 'line', +} + +interface CaretProps { + // The optional style of the caret. + caretStyle?: CaretStyle; + children: JSX.Element; +} + +const blockCaretStyle = { + color: '#FFFFFF', + background: '#333333', +}; + +const lineCaretStyle = { + boxShadow: 'inset 1px 0px #000000', + background: '#FFFFFF11', +}; + +const caretStyleToCssObject = (caretStyle: CaretStyle) => { + switch (caretStyle) { + case CaretStyle.block: return blockCaretStyle; + case CaretStyle.line: return lineCaretStyle; + default: return blockCaretStyle; + } +} + + +const Caret: React.FC = ({ + caretStyle = CaretStyle.block, + children, +}: CaretProps) => ( + {children} +); + +export default Caret; diff --git a/src/theme/ReactLiveScope/index.js b/src/theme/ReactLiveScope/index.js new file mode 100644 index 00000000..28159fcc --- /dev/null +++ b/src/theme/ReactLiveScope/index.js @@ -0,0 +1,27 @@ +import React from 'react'; +import ReactLiveScope from '@theme-original/ReactLiveScope'; + +// Components to make available to the editor. +// Note that adding the CodeBlock to the context seems to cause a webpack +// error, so for now I just use . +// import CodeBlock from '@theme/CodeBlock'; + +import AnnotatedCommand from '@site/src/components/AnnotatedCommmand/AnnotatedCommand.tsx'; +import AsciinemaPlayer from '@site/src/components/AsciinemaPlayer/AsciinemaPlayer.tsx'; +import Caret from '@site/src/components/Caret/Caret.tsx'; +import Image from '@theme/IdealImage'; + +const ReactLiveScopeWrapper = (props) => ( + <> + + +); + +// Add any custom components you want to have available in the React Live +// Codeblock component to the ReactLiveScopeWrapper below. +ReactLiveScopeWrapper.AnnotatedCommand = AnnotatedCommand; +ReactLiveScopeWrapper.AsciinemaPlayer = AsciinemaPlayer; +ReactLiveScopeWrapper.Caret = Caret; +ReactLiveScopeWrapper.Image = Image; + +export default ReactLiveScopeWrapper;