World of Textfiles: Emoji-based Summaries

As a software developer, I am empowered to build and control my life with plain text. This series explores ways that I'm trying to de-appify my life and be able to own my own data... with Plain Text.

(Thanks to @mikeormerod for reminding me to finish this post!)

One thing I've found myself doing a bunch recently is highlighting interesting lines in meeting or booknotes. I suppose you could do whatever you want, but I've been using ⭐️ for importance/insight, ❗️for actions, and ❓for questions. They just jump off the page as I am scrolling through my notes, and they are still just plain text!

After my last major study booknote on Lean UX, I wanted to be prepped for the upcoming class. I wanted all my questions easily accessible, so I used Drafts's arrange mode to copy and move all the questions to the top of the page. This gave me a great little overview of the whole book note, and a resource for asking questions during the class.

I found it so valuable, I started adding similar markup to other notes... and wrote a Drafts Action. It finds any line that begins with an emoji and a colon "⭐️:" and copies them and groups them by emoji at the top. This lets me be free to be creative with my emoji "tags," and decide what to do with them later.

Here's a walk-through, but you can download the whole js here on gist.

// Pull all lines with "<emoji> :" together, create headers with a "## <emoji>"
// and list the grepped lines after.

// this is the heading the summary will appear under.
// use something uncommon.
var magic_header = "Auto Summary";

var emoji_regex = /(?:- )?(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]).* ?: ?(.*)/g;

I'm pretty sure I got this emoji regex from somewhere on StackOverflow, there's no way I just magicked that out of nowhere. It does cover all emoji, including curly quotes and ellipsis (), something we'll cover later.

var highlights = {};
var content = draft.content;

var match = emoji_regex.exec(content);

Setting up some more variables... the main thing here is that we'll be storing the matches in an object called highlights, each emoji will be stored as the key mapping to an array of matching strings. To do this we'll need a function…

var pushNew = function(obj, key, string) {
  if (typeof obj[key] === typeof undefined) {
    obj[key] = [string];
  } else {

This function checks to see if there's a key already declared... if it exists, it just appends (push()) to that array, otherwise it creates the key with an array with the single match.

var automateHighlights = function(highlights) {
  var result = "\n\n## " + magic_header + "\n\n";

  for (let emoji in highlights) {
    if (!emoji.match(/…|“|”|’/)) {
      result = result + "### " + emoji + "\n\n";
      for (let index in highlights[emoji]) {
        result = result + "- " + highlights[emoji][index] + "\n";
      result = result + "\n"

  return result;

This last function is for the very end. highlights is the object. We iterate over its keys, and for each key we iterate over the values of highlights[emoji]… unless it's a few emojis that I don't care to match. I'm sure there may be others you may not want to match, you can add them to this "blocked" list here. (Might be a good little thing to refactor!)

while (match != null) {
  pushNew(highlights, match[1], match[2]);
  match = emoji_regex.exec(content);

With all the hard work done… here's the meat. While there are matches to be made, push a new match to the highlights object, and move the search forward.

if (draft.content.match("## " + magic_header)) {
  console.log("already ran!")
else {
  draft.content = draft.processTemplate("[[title]]")
                      + automateHighlights(highlights)
                      + draft.processTemplate("[[body]]");


It doesn't yet have an update function… so if you run it twice it'll match that it's already been run by looking for magic_header and you'll just get a message in the console. I suppose I could write some kind of begin and end marker to allow myself to delete and rebuild the index, but I haven't spent enough time on it.

If it hasn't been run, we protect the title, insert our new matching highlights template in the middle, and put the body underneath. It looks a little like this.

Here's what it looks like in action.

I've also considered making a custom set of actions to add these highlight/tags to a line as a custom set of Keyboard Actions in Drafts, but I haven't really needed it so far.

Hope this is helpful! Let me know via my contact form or twitter if you do something similar.

  • 2022-06-08 11:31:29 -0500
    Rename articles

  • 2022-02-08 13:48:30 -0600
    Update syntax highlighting

  • 2020-06-18 14:26:02 -0500
    Move everything to CST

    Don't know why I didn't do that before. It caused _no_ end of

  • 2020-06-14 15:51:50 -0500
    Update articles with series and series partials

    After the refactor, needed to move the series metadata to the actual

  • 2020-06-08 12:34:07 -0500
    Hack together more series pages

  • 2020-03-19 18:42:07 -0500
    Update the tags from "draft" -> "draftsapp"

  • 2019-10-21 21:09:29 -0500
    New post: Emoji summaries