Setting up my "blog"

or: getting emacs to fix all my problems

I've realized recently that I've never really had a place to just write things down on the internet that wasn't something like Twitter, Mastodon, or something else. Those sites are too ephemeral and short-lived to really serve as something where I can post longer-formed So now I think I'm going to put some work into this "blog" in the near future (you know, to finally use this domain I pay for 🙃). My goal for this blog is to treat it more like "blogumentation" for various ideas or notes I have to share rather than something with more intent. I don't expect anyone to read what I post here :).

As part of wanting to work on this blog, I of course had to setup some tooling to make it easier to write. This site is an overengineered NextJS application hosted on vercel and as such, I've got quite a bit of control over how the site gathers up posts and displays them on the page. So like any good markdown based blog, I've overengineered how everything works on my end in an attempt to make it "easier" for me to make new posts when I have an idea.

Reducing friction (with emacs)

Don't tell anyone, but lately I've been using emacs more than vim (I know, gasp). Granted, I've got evil-mode configured to make it feel more like home, but still. Emacs doesn't make for a very good text editor (vim is way faster), but it does make for a pretty good programmable editor (most of emacs is programmed in emacs lisp). So I wrote a little function which allows me to write a new post very quickly:

(defun ncw/title-to-slug (title)
  "Given a plain text title, convert it to a slug (lowercase with hyphens)"
  (let ((cleaned (replace-regexp-in-string "[^[:alnum:] ]" "" title)))
    (downcase (replace-regexp-in-string " " "-" cleaned))))

;; The main function to create a new blog post
(defun ncw/new-blog-post (title)
  (interactive "sPost Title: ") ;; Ask for a post title if invoked interactively
  (let* ((slug (ncw/title-to-slug title))
         (file (format "~/dev/website/posts/%s-%s.md"
                       (format-time-string "%Y-%m-%d")
                       slug)))
    ;; Create the markdown file for the post and insert the markdown header
    (with-temp-file file
      (insert (concat "---\n"
                      (format "title: \"%s\"\n" title)
                      (format "date: \"%s\"\n" (format-time-string "%b %d %Y"))
                      "---\n"
                      "\n\n"
                      "# " title "\n")))
    ;; Open the file in the editor
    (find-file-other-window file)))

All I have to do is M-x ncw/new-blog-post and emacs will ask me for a title for the post and open a new markdown file in the right location (my blog lives on my mac at ~/dev/website). From there I can just start writing whatever I was thinking about. Then, I can easily commit the new post to github using magit and vercel will automatically pick up on the changes and deploy the new revision of my website The goal here is to make it trivial to write a new post - in the past I always gave up on writing because creating the right markdown file name and everything was just too much friction.

Pasting Images

The trouble then is how I manage images. I don't want to have to open up my file explorer, copy files around, and setup paths manually... That's just a recipie for me to never use images. Instead I'd like to be able to take a screenshot of something on my mac, then "paste" the screenshot into the markdown file and have the image automatically put into the /public folder with some automatically generated name. Then, I'd like the markdown for a post to automatically embed the image.

This is pretty common in WYSIWYG editors like on medium or whatever, but isn't a builtin feature of really any markdown tooling (though VSCode may have an extension which does the job, I couldn't really convince it to work in the way I wanted it to).

I mostly use emacs in the terminal, so I can't really rely on it to have any access to the OS in any meaningful way. I'll have to rely on external tooling - mainly pngpaste. The macos clipboard is a little tricky, and the builtin tooling (pbpaste) won't paste images from your clipboard. This utility allows you to paste a png image from your clipboard by simply running pngpaste /path/to/out.png.

I tied all those tools together with this little bit of elisp code which seems to work pretty well so far:

(defun ncw/blog-paste-image ()
  (interactive)

  (let ((image-slug (format-time-string "%b-%d-%Y-%H-%M-%S.png")))
    ;; Create the image directory
    (shell-command "mkdir -p ~/dev/website/public/post/res/")
    ;; Paste the image to the filesystem
    (shell-command (format "pngpaste ~/dev/website/public/post/res/%s" image-slug))
    ;; And insert the image markdown
    (insert (format "![ALT](/post/res/%s)" image-slug))))

There's definitely a better way to do this with builtin elisp, but I'm not too worried. Eventually, it will probably make sense to upload these images to somewhere other than the public/ folder, because I end up paying more for that traffic than I would on something like S3, but that's future Nick's problem.

Conclusion

So yeah, I'm gonna start writing here more. Who knows how often, but I'll give it a shot :) The above code can be found in my poorly organized emacs dotfiles here.