How I make memes inside code
Tags: meme, vscode, extension
Published: 2021-08-01 06:35:59

Just another day, I was making memes on reddit, and writing code in the interval. It suddenly struck me, why can't I do both at the same time? Making memes inside code is totally possible, just make ascii based memes inside comments. However, it's very time consuming to 

1. Find the meme template
2. Download it.
3. Convert it to ascii format
4. Paste it into IDE
5. Make them as comments

After a few tries, I decided to make a vscode extension to speed up this process by combing all those steps into one: Hitting a hotkey on your keyboard.

Extension Link: https://marketplace.visualstudio.com/items?itemName=llldar.vsc-memer

Github link: https://github.com/llldar/vsc-memer

### Begin

In order to write a vscode extension, first you need `yo` and `generator-code`, install them by

```bash
npm install -g yo generator-code
```

After installation you can

```bash
yo code
```

And the command line will interactively prompt you a number of options and you can follow them one by one.

After the steps, you will have a working `hello-word` vscode extension.

### Implementation

I was planning supporting 4 commands for this extension

- insertRandomMeme
- copyRandomMeme
- insertMeme
- copyMeme

In order to achieve those, I need use vscode extension API extensively.

To insert code, you first need to get current selection position, then you can insert text into those places.

```typescript
editor?.selections.forEach((v) =>
  edit.replace(v, comment(getRandomMeme()))
);
```

One thing you need to know is that vscode keeps the inserted text selected after insertion, you need to unselect the text by clearing selection

```typescript
editor.selection = new vscode.Selection(
  editor.selection.end,
  editor.selection.end
);
```

For copying text to clipboard, it's very easy, just use some simple vscode api, you need to notify users after copy

```typescript
vscode.env.clipboard.writeText(comment(getRandomMeme()));
vscode.window.showInformationMessage('Random meme copied to clipboard');
```

Now inserting random memes are easy, while if you want to insert a meme selected by user, you need to have user input. Fortunately, we have `QuickPick` api that allows user to pick one from our list:

```typescript
const options = Object.keys(memes).map((label) => ({ label }));
const quickPick = vscode.window.createQuickPick();
quickPick.items = options;
```

Show the QuickPick on user command:

```typescript
quickPick.show();
```

Receive user input from callback, hide the quick pick after selection:

```typescript
quickPick.onDidChangeSelection(([{ label }]) => {
  vscode.env.clipboard.writeText(
    comment(memes[label as keyof typeof memes])
  );
  vscode.window.showInformationMessage('Random meme copied to clipboard');
  quickPick.hide();
});
```

One more thing we need to consider, memes need to be wrapped inside comments, different language have different comment styles, we need to allow user to configure those by adding configuration inside `pakcage.json` like:

```json
"configuration": [
    {
        "title": "Meme maker",
        "properties": {
            "vsc-memer.commentStyle": {
                "type": "string",
                "default": "line",
                "enum": [
                    "line",
                    "block"
                ],
                "enumDescriptions": [
                    "line comment style, like //",
                    "block comment style, like /* */"
                ],
                "description": "Type of comment style"
            },
            "vsc-memer.lineComment": {
                "type": "string",
                "default": "//",
                "description": "Symbol of line comments the generated meme should be wrapped in"
            },
            "vsc-memer.blockCommentLeft": {
                "type": "string",
                "default": "/*",
                "description": "Symbol of left side of block comments the generated meme should be wrapped in"
            },
            "vsc-memer.blockCommentRight": {
                "type": "string",
                "default": "*/",
                "description": "Symbol of right side of block comments the generated meme should be wrapped in"
            }
        }
    }
],
```

Note they needs to be under `contributes` block, otherwise they would do nothing.

Adding comment mark is easy, but one more thing we need to consider: windows and macOS/linux have different line endings. Also vscode can override system settings, it becomes more and more complicated now.

First we need to read vscode config `files.eol`, if it's not set to `auto`, we need to insert the option value.

If it's `auto`, we need get operating system's EOL by using node api `os.EOL`.

After implementing all the features, we need to register all the commands like:

```typescript
context.subscriptions.push(insertRandomMeme);
context.subscriptions.push(copyRandomMeme);
context.subscriptions.push(insertMeme);
context.subscriptions.push(copyMeme);
```

### Debugging

It's very straight forward, just hit `F5` and you can debug in the child vscode window from host vscode window.

### Publish

After you finished your code, you need another tool to publish it `vsce`, install it by:

```bash
npm i -g vsce
```

Also you need to have an [Azure devops](https://azure.microsoft.com/services/devops/) account, and [create a publisher](https://marketplace.visualstudio.com/manage) in vscode market place.

You also need to generate a personal access token with permission to manage you vscode marketplace and all accessible organizations from Azure devops.

Read [offical documentation](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) for more information.

After you have your personal access token you can

```bash
vsce login <your_publisher_name>
```

Then you can just

```bash
vsce publish
```

### Promote

A great extension needs create promotion, since it's meme making extension, I decided to promote it mainly on reddit using memes. If you have discord server, twitter following, YouTube channel, you can always use them to promote.