zck.orghttps://zck.orgThe personal site of Zachary Kanfer. Less: a Survival Guidehttps://zck.org/less-a-survival-guidehttps://zck.org/less-a-survival-guide05 Jun 2024 00:00:00 EST

I noticed recently that I was having trouble moving around in less. I could arrow up and down, but that took a lot of work. I could hit space to go a whole screen down, but unlike in a web browser, shift-space also scrolls down. How could I scroll up a screen? On some terminals, Page Up and Page Down work, but not in others.

It's a confusing mess.

So, after years and years of using less, I finally looked up how to move around natively. Native less commands will work everywhere! Here's the most useful things I found. As a bonus, I also ran into some ways to configure less to be more helpful!

General less commands

h

Open a summary of less commands and options.

q or ZZ

quit less. This isn't exactly navigation, but is pretty important.

Navigation

These commands move around in the output.

up, down

Move a single line up or down.

left, right

Move a half screen left or right.

f

Move forward (down) a whole screen.

b

Move backward (up) a whole screen.

d

Move down half a screen.

u

Move up half a screen.

g or <

Go to the beginning of the output.

G or >

Go to the end of the output.

They also work with the control modifier, if for some reason you want to press more keys.

I've been finding that d and u are pretty easy to remember, but a lot of the other ones are more difficult. Some of the commands are taken from vi, so if you already know vi, that helps.

Searching

When I'm using less, there's generally a lot of text. Fortunately, less lets you search in the text it's displaying!

/

Begin a search. Type your query, then press return to jump to the next result.

n

Go to the next match for the search.

N

Go to the previous match for the search.

Options

Less is actually configurable! Here are some command line options. If you prefer – perhaps because less has been spawned from another program – they can also be typed once less is running.

-i

Toggle case sensitivity for searching, unless the search query contains capital letters.

-J

Put a marker on the left edge of the screen on every line that the current search matches.

-W

After a forward jump of more than one line, highlight the first new line. Unfortunately, this doesn't work for jumping backwards.

--status-line

When a line is marked (as with -W), mark the whole line instead. Frustratingly, the version of less on MacOS is too old to have this option; it was only added in 2021.

--incsearch

Start searching as soon as you start typing the search query.

--use-color

Use color in less's output!

-R

Output incoming escape characters in raw form. This helps when the input contains these control characters, like when running git diff or a similar command.

Enabling options permanently

The settings can be set in an environmental variable LESS.

For example, if you're using bash, you might add this to your ~/.profile:

export LESS="-J -i -W --status-line --incsearch --use-color -R"

Or, for Fish shell, run this command:

set -Ux LESS "-J -i -W --status-line --incsearch --use-color -R"

I set them in my shell, and now everywhere I use less, it works the way I want it to work. More or less.

]]>
Formuladle!https://zck.org/numberdle?variant=formuladlehttps://zck.org/numberdle?variant=formuladle14 Jan 2024 00:00:00 ESTFormuladle!]]> Factordle!https://zck.org/numberdle?variant=factordlehttps://zck.org/numberdle?variant=factordle10 Dec 2023 00:00:00 ESTFactordle!]]> Numberdle!https://zck.org/numberdle?variant=rationerdlehttps://zck.org/numberdle?variant=rationerdle03 Dec 2023 00:00:00 ESTRationerdle!]]> Easily repeat Emacs functions: a repeat posthttps://zck.org/emacs-repeat-mode-emacs-repeat-modehttps://zck.org/emacs-repeat-mode-emacs-repeat-mode05 Sep 2023 00:00:00 EST

"Winning takes talent, to repeat takes character."

– John Wooden

Remember Emacs's transient maps?

I posted about them all the way back in 2016. Transient maps temporarily add a keymap that is active only for a single keypress. It enables things like repeating commands, or making a set of similar commands easier to call one after another.

Well, times have changed.

In 2022, Emacs 28.1 was released. This release added repeat mode, a piece of functionality that's similar to transient maps. Like transient maps, repeat mode allows for different actions to be triggered by keypresses after a function is called. Unlike transient maps, repeat mode works without modifying the source of the function being acted on.

But repeat mode is confusing.

Like "repeat mode" suggests, it lets the user repeat commands. If that were all it does, repeat mode would be useful, but it would duplicate C-x z (#'repeat). Luckily, repeat mode has more functionality than just repeating.

Maybe even the name is confusing.

Using repeat mode

Enable it with (repeat-mode 1).

Now, every time a command is called, Emacs will look at the 'repeat-map property on that specific command. If it finds a keymap there, Emacs will bind it as a transient map after running the command.

To use it, add a keymap to the function with (put #'original-function-name 'repeat-map 'keymap-for-the-function)

If you look carefully, you'll notice that I lied before.

There isn't a keymap as the property; there's a symbol. That is, the keymap name is quoted. It can't directly be a function, like a make-keymap call. Instead, make a variable and set its value to the desired keymap, like (defvar my-example-repeat-map (define-keymap "h" #'function-to-repeat)).

Once we do all that, after calling #'original-function-name, the user can call #'function-to-repeat by pressing h.

I suspect repeat mode doesn't look directly for a keymap to encourage variable use. That way, users can add and remove bindings from the keymap after it's added to the function. But that's just a guess.

Not just for repeating

Remember how I said repeat mode was confusing? Well, it sure is. Unintuitively, repeat mode is not just for repeating. It can be used to call a whole menu of commands after the original function.

If you're writing your own functions, I'm not sure whether to use repeat maps vs transient maps. As far as I can tell, the result is basically the same, except for two things:

  1. Repeat-maps can be listed by #'describe-repeat-maps. I don't think this is especially useful.

  2. Repeat-maps automatically message the user the keys that are bound in that map, although they do not tell the user what the keys do. Transient maps don't provide any guidance to the user.

On the other hand, repeat mode means you can change any given function, not just ones you're coding yourself.

An example!

Let's say you want to capitalize, lowercase, and upcase words easily. We want to choose between pressing c to call #'capitalize-dwim, d to call #'downcase-dwim, and u for #'upcase-dwim. First, let's create a keymap that binds those three keys.

(defvar change-of-case-keymap  (define-keymap    "c" #'capitalize-dwim    "d" #'downcase-dwim    "u" #'upcase-dwim))

Now, we set that map as the 'repeat-map' property on the three functions.

(put #'capitalize-dwim 'repeat-map 'change-of-case-keymap)(put #'downcase-dwim 'repeat-map 'change-of-case-keymap)(put #'upcase-dwim 'repeat-map 'change-of-case-keymap)

Now, after running any of those three functions, the keymap is activated, and it's possible to run any of the three functions again with a keypress.

Go and repeat!

That's all I have to say. Go and repeat.

Go and repeat.

]]>
Announcing caser.el, a package to camelCase, dash-case, and snake_case texthttps://zck.org/announcing-caser-elhttps://zck.org/announcing-caser-el27 Aug 2023 00:00:00 EST

Now announcing the v0.1 release of caser.el! This package contains functions to change text from camelCase to dash-case to snake_case and back.

Caser.el supports any language Emacs does. It is tested on English, Icelandic, German, and Korean.

A more full description is found at its repository, and can be installed from Melpa. Its current build status is build status.

]]>
Automatially Balance Your Emacs Windowshttps://zck.org/balance-emacs-windowshttps://zck.org/balance-emacs-windows14 Jul 2023 00:00:00 EST

Emacs windows easily get unbalanced.

After calling split-window-right twice, there are three windows. Rather than being all the same size, two of them take up a quarter of the frame each, and the third is half as big as the frame.

Three windows, of different sizes.

Or, if there are already three equally-sized windows, closing one window leaves one of the remaining windows twice as big as the other.

Two windows, of different sizes.

To me, that's unbalanced.

I want the windows to be the same size. Whether I got to two windows by starting at one and opening another, or starting at three and closing one, those two windows should have the same layout.

Two balanced windows.

So I'd manually balance them. Every time I opened or closed a window, I'd press C-x + to run #'balance-windows. Then, all the windows would be the same size, no matter if I'd just opened or closed one.

Three balanced windows.

Then I realized that no matter how many windows are open, I want them to be the same size. This is manual work! Too much manual work. Why doesn't Emacs do that for me?

I wrote some code. Now it does.

(seq-doseq (fn (list #'split-window #'delete-window))  (advice-add fn              :after              #'(lambda (&rest args) (balance-windows))))

This is a straightforward use of Emacs's powerful advice functionality. Every time the window configuration is changed, we call the function balance windows, to keep all the windows equally sized.

And then everything is in balance.

UPDATE

A kind stranger wrote in about the variable window-combination-resize.

If this variable is t, splitting a window tries to get the space proportionally from all windows in the same combination.

I think this is relatively confusing, but it does seem to do what we want. So the fix code is updated to:

(setf window-combination-resize t)

So things are still in balance, but lighter. If confusing.

]]>
An Improved Emacs Searchhttps://zck.org/improved-emacs-searchhttps://zck.org/improved-emacs-search16 May 2023 00:00:00 EST

Emacs's incremental search is very powerful. Rather than wait to show results until the search query is completely typed, it immediately begins searching once the first character is typed, updating the search as more letters are pressed. This makes it very responsive, and provides answers immediately.

But not everything is great about it.

By default, the incremental search doesn't provide any context. How many matches are there? Is this result near the beginning or the end?

incremental search, as default

Computers are better than humans at counting. Let's make Emacs count the matches for us.

(setq isearch-lazy-count t)

Enabled lazy counting!

This feature is called lazy counting. I'm not sure if it's calling us lazy for using it, or saying that Emacs will lazily count the matches.

When enabled, Emacs displays the number of search results in the minibuffer, along with the index of the current search result. It's very useful to add context.

However, the default display is difficult to read. We can change that too.

(setq lazy-count-prefix-format nil)(setq lazy-count-suffix-format "   (%s/%s)")

This puts the counts at the end of the search message, not the start.

A nice experience!

Now that's a feature that counts!

]]>
Nix Development Shellshttps://zck.org/nix-development-shellshttps://zck.org/nix-development-shells14 May 2023 00:00:00 EST

I recently wanted to develop some Emacs code. But I didn't want to do the work of finding all the different dependencies needed to install them.

I'm running NixOS, so luckily, there is a command for that.

nix develop nixpkgs#emacs

nix develop will open a shell with all the dependencies needed to develop that package.

This is a flake-based command, so I believe it needs to be building a flake.

As above, you need to specify that the package is inside nixpkgs if you're trying to use one from there. Do that with nixpkgs#your-package-here. You can presumably develop flakes from elsewhere by specifying different locations.

After running the command, I was able to build Emacs without having to install a single dependency! Thanks, Nix!

]]>
Simple tricks with Imagemagickhttps://zck.org/imagemagick-trickshttps://zck.org/imagemagick-tricks06 May 2023 00:00:00 EST

Imagemagick is a powerful tool to manipulate images on the command line. It can do things like add a border, crop an image, or convert an image from one format to another. But because it has so many features, it's difficult to figure out how to do the thing you want to do.

Here are some things I've done with it, for my own reference. Maybe it's useful to you too.

Most of these examples use this image for an input. It's a 400 by 400 pixel version of my logo on a green background.

My logo. This image is used as the starting image for commands on this page.

Convert an image between formats

This is possibly the simplest thing you can do with Imagemagick.

magick logo.png logo.jpeg

My logo, but as a jpeg!

This takes the first argument (in this case, a PNG) and outputs it as the second argument (in this case, a JPEG).

Resize an image

Resize an image! The -resize argument resizes an image – in this example, to 100 by 200 pixels.

magick logo.png -resize 100x200 resized-1.png

My logo, resized but not to the size I thought it would be.

Wait, that isn't 100 by 200 pixels! The command resized it to 100 by 100 instead. Why is that?

It turns out the 100x200 argument is a geometry argument. 100x200 means "Maximum values of height and width given, aspect ratio preserved". So the width is a maximum of 100 pixels, and since the aspect ratio is kept as 1:1 (the same as the original image) the height also is forced to be 100 pixels.

To force the resize to the exact size given, pass an 100x200! geometry argument:

magick logo.png -resize 100x200! resized-2.png

My logo, resized to a new aspect ratio.

To preserve the aspect ratio, pass only one of the width x height arguments. This results in a 200 by 200 pixel image.

magick logo.png -resize x200 resized-3.png

My logo, resized with a set width, but keeping the same aspect ratio.

Or even make each direction 50% smaller! Because logo.png was 400 by 400 pixels, this also results in a 200 by 200 pixel image.

magick logo.png -resize 50% resized-4.png

My logo, resized to 50% of the previous size.

For more information about specifying the size, read about the geometry argument.

Add a border

In most documents, images look way better with a border. For example, a grey 5 pixel border:

magick logo.png -bordercolor grey -border 5 bordered.png

My logo with an added border.

Crop an image

There are several options to crop an image, removing from its edges.

Crop, well, crops an image, but in a croppy crappy way. Its arguments are the size of the image you want to save. I almost always find it more intuitive tell how much to remove instead, like "trim 100px off the left". It seems designed more for editing images down to a specific size.

To crop to a 100 by 200 pixel image starting at the 10th pixel from the left, 20th pixel down:

magick logo.png -crop 100x200+10+20 cropped-1.png

My logo, cropped to an exact size.

The frustrating part with this is that to take another pixel off the left, you have to both change the offset (for determining how many pixels on the left to remove), but also the size, because you don't want to cut less from the right side. To cut one more pixel off the left:

magick logo.png -crop 99x200+11+20 cropped-2.png

My logo, cropped one more pixel over from the last one.

This is more complicated than it should be to move one pixel over – you have to calculate the new width as well as specify the starting pixel. Instead, shave removes the same size from the top and bottom of an image, and the same size from the left and right. To remove 30 pixels from the left and right, and 100 from the top and bottom:

magick logo.png -shave 30x100 cropped-3.png

My logo, cropped with -shave.

This, too, isn't quite what I want. Usually, I want to specify different offsets for the left and right side. Or different offsets for the top and bottom. But, as far as I'm aware, you can't. I wish you could.

Also, the geometry argument is somewhat complicated – if you just want to make the image shorter, setting the geometry argument to 100x results in width / 100 images, each 100 pixels wide. This is not what I would want. Instead, set the geometry to 100x+0+0. Why does this work? I have no idea.

A warning about cropping

Sometimes, you need to add +repage when cropping. I don't really know when. It's definitely not always, as the documentation suggests. None of the examples here use it.

Add a background to a transparent image

I used this to create the image at the top of this page that's used as the base for all of these images, starting with a transparent version of my logo.

My logo, with a transparent background.

We'll use the -alpha remove option to remove the transparency. This causes the transparent channel of the image to be replaced with the background color, so we previously need to set the background color to what we want.

magick logo-transparent.png -background red -alpha remove with-background.png

My logo, with an added background.

Move an image around

Sometimes, we want to shift an image, moving it around. We can do that with the -page option. This will move the image as specified by another geometry argument. We also have to add -layers flatten, as that will use the current background color, create a canvas the size of the image, and crop out anything outside of that canvas. Or something. I won't pretend to completely understand how it works without flattening, but it's required.

magick infile.png -page +100 -layers flatten logo-moved.png

My logo, moved to the side.

I used this method to make a bunch of pngs for the next example.

Animate a gif

Let's make an animated gif! Assume we have a folder with a series of png files. We want to combine them into one gif.

magick -delay 10 -loop 0 *.png animated-logo.gif

My animated logo.

The -delay argument is in hundredths of a second, not milliseconds. This seems a little silly, but who ever let that stop them? Apparently this follows from the gif spec.

Passing -loop 0 means to loop forever.

Odd different difference between convert, magick, etc

Imagemagick has both magick and convert commands, along with many others. It's not well-documented, but my understanding is that using the magick version is preferable.

]]>
Re-move files in Emacshttps://zck.org/emacs-move-file-againhttps://zck.org/emacs-move-file-again28 Jun 2022 00:00:00 EST Back in 2016, I wrote an Emacs function to move files in Emacs. After my work agreed to sign the employer disclaimer, I'm able to contribute to Emacs again.

So I did.

After some discussion, the function was accepted into Emacs. There were a few changes, including renaming it to rename-visited-file.

If you build Emacs from source, the function is now in the Emacs git repository. If you don't build from source, it will be available in the next release. If you run Vim, it's not available at all.

However it gets used, this has been a great way to shrink my Emacs config!

]]>
Testing buffer-modifying Emacs code (again)https://zck.org/testing-buffer-modifying-emacs-code-againhttps://zck.org/testing-buffer-modifying-emacs-code-again02 Jun 2022 00:00:00 EST

There are no straight lines in nature. - Antoni Gaudí

I previously published an article about testing buffer-modifying code: functions whose behavior is not encapsulated by their return value, like upcase-word or isearch-forward. Instead, they are called to modify the current buffer. We might want to test upcase-word as follows.

(should (equal (with-temp-buffer (insert "hi there")                          (goto-char (point-min))                          (upcase-word 2)                          (buffer-string))        "HI THERE"))  

This works, but it's hard to read – the setup code, the test code, and the comparison are all mingled together.

So the previous post created a macro to help. This macro inserted the first argument into a temp buffer, then ran the other arguments as code. Finally, it returned the entire buffer as a string. This let us make assertions against the buffer after the body code has been run. For example, the above code can be replaced with:

(should (equal (old-on-temp-buffer "hi there"                            (upcase-word 2))        "HI THERE"))

With this macro, we can test the behavior of upcase-word on the buffer. But on a recent train trip, I thought of a way to make it more user-friendly.

Before showing the new macro, let's look at the problems with the old on-temp-buffer.

Downside 1: Placing Point

One of the downsides of this version was having to move point to the correct location. The longer the input text, the more complicated the code to move point.

(should (equal (old-on-temp-buffer "isn't this\nDELETE annoying?"                            (next-line)                            (forward-char 6)                            (delete-char -7))        "isn't this annoying?"))

At a glance, you can't tell which part of the code moves point to the right location, and which part is the code we are testing. Wouldn't it be nice if we could the string itself could include where point should be?

Well, now we can. If you put in a pipe character, on-temp-buffer will put point there.

(should (equal (on-temp-buffer "this is\nDELETE| easier!"                        (delete-char -7))        "this is easier!"))

Isn't that easier? If there is no pipe character, point is placed at the beginning, just as in the old version.

(should (equal (on-temp-buffer "should I go?"                        (insert "where "))        "where should I go?"))

Downside 2: Retrieving Point

Some functions move point. To check where point ends up, on-temp-buffer-point returned the value of point:

(should (equal (on-temp-buffer-point          "this is a lot of words"          (forward-word 2)          (upcase-word 2))        14))

But now, it places a pipe character where point is.

(should (equal (on-temp-buffer-point          "this is a lot of words"          (forward-word 2)          (upcase-word 2))        "this is A LOT| of words"))

And combined with setting point at the beginning, it's even easier:

(should (equal (on-temp-buffer-point          "this is |a lot of words"          (upcase-word 2))        "this is A LOT| of words"))    

Et tu, pipe

But what if you need pipe characters in your body text? Escape them. "\\|" will be placed into the test buffer as a single pipe character. Similarly, if the test buffer has pipes in the output string, on-temp-buffer-point escapes them.

(should (equal (on-temp-buffer-point          "not\\|hing to see"          (forward-word 2)          (insert "|")          (forward-word)          (insert "|")          (forward-word))        "not\\|hing\\| to\\| see|"))

After running all the code, point was at the end of the buffer. So on-temp-buffer-point puts a pipe there. The other pipe characters are escaped, indicating actual pipe characters in the buffer.

New Code

This is the entire modified code.

(defmacro on-temp-buffer (string &rest body)  "Insert STRING into a temp buffer, then run BODY on the temp buffer.Point starts at the beginning of the buffer, or where a pipe characteroccurs.  To insert an actual pipe, include two pipes.After running BODY, the entire buffer is returned as a string."  (declare (indent 0) (debug t))  `(with-temp-buffer     (insert ,string)     (on-temp-buffer//preprocess-buffer)     ,@body     (buffer-string)))(defmacro on-temp-buffer-point (string &rest body)  "Insert STRING into a temp buffer, then run BODY on the temp buffer.Point starts at the beginning of the buffer, or where a pipe characteroccurs.  To insert an actual pipe, include two pipes.After running BODY, the entire buffer is returned as a string.  Inthis returned string, point is indicated by a pipe character.  Pipecharacters in the string are replaced with a double pipe."  (declare (indent 0) (debug t))  `(with-temp-buffer     (insert ,string)     (on-temp-buffer//preprocess-buffer)     ,@body     (on-temp-buffer//postprocess-buffer-for-point)     (buffer-string)))(defun on-temp-buffer//preprocess-buffer ()  "Preprocess the current buffer before body code can run.To do this:1. Move point to the location of a single pipe by itself.2. Replace all escaped pipe characters (\\|) with a single pipe."  (goto-char (point-min))  (let ((point-to-start-with (point-min)))    (while (re-search-forward (rx (or "|" "\\")) nil t)      (let ((string-matched (match-string 0)))        (delete-char -1)        (when (equal "|"                     string-matched)          (setf point-to-start-with (point))))      (forward-char 1))    (goto-char point-to-start-with)))(defun on-temp-buffer//postprocess-buffer-for-point ()  "Process the current buffer so it indicates where point was.This is for use after running body, for on-temp-buffer-point.To do this:1. Place a backslash before each pipe character.2. Insert a single pipe character where point was when this functionwas called."  (let ((point-to-return (point)))         (goto-char (point-min))         (while (search-forward "|" nil t)           (when (< (point) point-to-return)             ;;we're going to insert a character before point-to-return,             ;;so increase it by one.             (setf point-to-return (1+ point-to-return)))           (backward-char 1)           (insert "\\")           (forward-char))         (goto-char point-to-return)         (insert "|")))

Happy testing!

]]>
Change Emacs's Default Behaviorhttps://zck.org/change-emacshttps://zck.org/change-emacs15 Apr 2022 00:00:00 EST People say you should leave Emacs's defaults unchanged.

Emacs is unbelievably customizable. Nearly any key can be changed. But there's advice given to rely on the defaults; they have been honed over years and years to be the best for everyone. I disagree.

What's best for everyone might not be best for you.

For example, C-z minimizes the Emacs frame. But I've never used it on purpose. I'd hit it by accident, surprising me when Emacs disappeared.

For nearly a decade, I hoped to get used to it. After all, haven't the default keybindings been carefully planned out? Aren't they perfect? I say no.

Your perfect configuration might be very different from someone else's.

Your needs are not the average user's needs, and your solutions should be different too. So change your Emacs to work with you.

You can override existing keybindings with improved functions:

  • M-c on my Emacs goes to #'capitalize-dwim, because that's better than #'capitalize-word.
  • I've replaced C-M-f, C-M-k, and other s-expression navigation functions with smartparens' versions.

But we can go further than replacing functions with better-behaved versions. Here are some other ways you might want to change Emacs's default behavior:

  • Disable the toolbar and menubar. Take the screen space back.
  • Hide the startup screen. Make your Emacs boot right to *scratch*.
  • Don't use the custom file. Configure everything with Emacs Lisp.

If you treat Emacs as unchangeable, you're missing out on the best parts.

After all, Emacs was made to let you change it.

]]>
Have Emacs questions? Ask emacs!https://zck.org/ask-emacshttps://zck.org/ask-emacs07 Apr 2022 00:00:00 ESTAnyone who works with Emacs has many questions about it.

I've been using Emacs for over fifteen years. Packages I've created have over 50,000 downloads, I've presented at EmacsConf 2020, and I co-organize EmacsNYC. Over all this time learning about Emacs, I've had a lot of questions. It turns out that the best place to ask questions about Emacs…is Emacs!

Here's five ways to ask Emacs questions.

  1. The Emacs tutorial – C-h t

    Emacs's built-in tutorial is incredibly well-written. It takes the reader from zero knowledge all the way through undo and redo, autosaving, and window management. It's even interactive!

  2. Show functions and variables – C-h f, C-h v

    Press C-h f, then type the name of a function to view the documentation for that function. C-h v views a variable's documentation. If Emacs's source is installed, you can click a hyperlink to go the function's source.

    Emacs's documentation is comprehensive. Like you might expect, it explains what a function does and what its arguments are. But more than that, the documentation viewer even also tells you what keypresses that function is bound to! This works not only for built-in key bindings, but any you have added as well.

  3. Show what function is bound to a particular keypress – C-h k

    To ask Emacs what will happen when a certain key or series of keys is pressed, type C-h k, then the key you are interested in. This brings up the same detailed documentation from C-h f.

  4. Show what keys are bound in the current buffer – C-h b

    If you don't know what you can do in the current buffer, ask Emacs! C-h b lists all the functions currently bound.

    If you have a multi-key binding, you might not know what comes next. After beginning any prefix, press C-h to show bound keys after that prefix. Even an Emacs expert can find something new with C-x C-h.

  5. View documentation about active major and minor modes – C-h m

    To see documentation for the modes that are currently active, ask Emacs! C-h m displays the mode descriptions plus bound keys.

Emacs inspires many questions. What's the quickest way to answer them? Ask Emacs.

]]>
Magic Stringshttps://zck.org/magic-stringshttps://zck.org/magic-strings05 Aug 2021 00:00:00 EST

One piece of programming advice is that one shouldn't use numbers in code unless they're stored in a variable or constant. Using a number as a bare value – often called a "magic number" – gives no context as to why that number is being used.

totalWidth = getSize() + 272;

Why 272? Why not 113? Instead, one is encouraged to use constants.

final int WINDOW_PADDING = 272;totalWidth = getSize() + WINDOW_PADDING;

This is better, because it prevents typos. But simply using a constant doesn't ensure readability. In string variables, there's an antipattern I'm calling magic strings.

final String USE_FOOBAR_SYSTEM = "use_foobar_system";

While the value is stored in a variable, the variable name merely repeats this value. The name doesn't help the reader understand what it's there for. These variables are no better than a numeric constant like:

final int THREE_HUNDRED_SEVENTY_TWO = 372;

The code does use a constant, but its name doesn't explain why the constant is there. Better to give it a name that explains what it's used for.

final String FOOBAR_SYSTEM_FEATURE_FLAG_NAME = "use_foobar_system";

This way, the name alone clearly indicates what it's used for. And clarity is a great goal to have in programming. As Harold Abelson and Gerald Jay Sussman have said,

…programs must be written for people to read, and only incidentally for machines to execute.

]]>
Hide Emacs's Customizehttps://zck.org/hide-emacs-customizehttps://zck.org/hide-emacs-customize21 Jul 2021 00:00:00 EST

If you don't actively use Emacs's customize functionality, it can be frustating when Emacs changes the custom-set-variables block in your init file. For example, when version controlling your init file, you have to skip over these diffs.

So, instead of letting customize make changes to your init file, we can redirect it elsewhere.

(setq custom-file "~/.emacs.d/custom.el")(when (file-exists-p custom-file)  (load custom-file))

Because none of your other config will go there, it can be safely added to your version control's ignore file. Even though it won't bother your VCS, it will still be loaded by Emacs, on the off chance you want anything set by customize.

Personally, I prefer to not use customize at all, because changes in it pop up at what appear to be random times. In addition, I often want to annotate or group my configuration, which is harder to do with customize. So when I make changes to my Emacs config, I prefer to do it in Lisp code in my init file.

Or, if you're lawful evil, you could set the custom-file variable with M-x customize.

]]>
Fixing Firefox 89's right-click menu on macOShttps://zck.org/firefox-macos-right-click-keyboardhttps://zck.org/firefox-macos-right-click-keyboard07 Jun 2021 00:00:00 ESTFirefox 89 changed right-click functionality on macOS. Previously, in a right click menu, typing a letter triggered an option in the menu. For example, rightclicking on a link and pressing t would open the link in a new tab.

But with the June 1 release, that is no longer the case. Now, pressing a letter highlights a menu item, but does not trigger it. It even highlights a different menu item from before. It is a side effect of using the native context menus on macOS.

Native context menus: Context menus on macOS are now native and support Dark Mode.

We can fix this by changing the about:config setting widget.macos.native-context-menus to true. Then Firefox uses its own context menus, so typing a letter triggers the menu item, as in previous browser versions.

Interestingly, this change was landed for a bug reported a long time ago in the year 2000.

]]>
Easy Quil screenshotshttps://zck.org/easy-quil-screenshotshttps://zck.org/easy-quil-screenshots28 May 2021 00:00:00 EST

When I started making generative art, I was excited to share the art I made. I took screenshots and manually cropped them to only the part of the desktop containing the art. As you might imagine, this process was completely foolproof, not to mention quick and easy.

No, wait. It was error-prone, boring and repetitive. But computers can do boring repetitive tasks for us! And whenever my computer starts to complain about having to play the same video over and over, I just unplug it.

Point being: I'm using Quil, a Clojure library based on Processing. Quil has a function save-frame:

save-frame: Saves an image identical to the current display window as a file.

We could call that function at the end of generating the art. That would work, but I render my art a few times with different random values, and manually pick some to keep. Like a child's drawings, some art is better thrown away. Luckily, Quil's sketch function has a parameter that runs a passed-in function any time a key is pressed.

:key-pressed - Called every time any key is pressed.

So we write a function that saves the current artwork as a picture when the s key is pressed.

(fn [] (when (= \s (q/raw-key))         (q/save-frame "/path/to/save/to.png")))

And use it in a sketch:

(q/sketch :size [width height] :draw my-draw-function :key-pressed (fn [] (when (= \s (q/raw-key))                       (q/save-frame "/path/to/save/to.png"))))

Now, anytime the s key is pressed, the current sketch is saved to the path /path/to/save/to.png.

That's fine, but we can do better. Let's make a function to generate this function. This way, we can call it from different artworks without having to copy and paste the body around. This is a common pattern I have with helper methods – start by making them in one work, then move them to a common library. It's satisfying to build your own package of useful functions.

(defn key-press-fn-creator  []  (fn []    (when (= \s (q/raw-key))      (q/save-frame "/path/to/save/to.png"))))

Now, rather than always saving to the same path, let's save to a better location.

  1. Save pictures inside a base folder specified in a variable base-output-folder.

  2. Inside that folder, use a folder for the current year. This means that once we've been making art for a while, we'll have an idea when we created each specific file.

  3. Take the name of the work as an argument to the function, and use that as the next folder.

  4. Explicitly save the random seed at the beginning of my work. We can reuse the seed to regenerate the same artwork, and lets us save more than one screenshot from the same code. We can use the seed as the filename to differentiate different saved versions of the same work.

(def base-output-folder "/path/containing/art/screenshots")(defn key-press-fn-creator  [work-name]  (fn []    (when (= \s (q/raw-key))      (let [file-path (format "%s/%s/%s/opus-%s.png"                              base-output-folder                              (q/year)                              work-name                              (q/state :seed))]        (q/save-frame file-path)))))

Because Quil doesn't expose the seed it uses, we generate a new one, store it in the state atom, and tell Quil to use it instead of the default seed.

;; in the setup function.(swap! (q/state-atom)       assoc       :seed       (q/random (Math/pow 10 9)))(q/random-seed (q/state :seed))

This function is used in the sketch call:

(q/sketch ;;; other code elided :key-pressed (key-press-fn-creator "bubbling-brook"))

Finally, pressing ESC to quit the sketch is too much work. Let's close the sketch when q is pressed.

(defn key-press-fn-creator  [work-name]  (let [actions {\s (fn []                      (let [file-path (format "%s/%s/%s/opus-%s.png"                                              base-output-folder                                              (q/year)                                              work-name                                              (q/state :seed))]                        (q/save-frame file-path)))                 \q (fn []                      (q/exit))}]    (fn []      (when-let [action (actions (q/raw-key))]        (action)))))

There's more that could be done, but this post is long enough. Maybe I'll make a tool so I don't have to automatically crop blog posts.

]]>
!!Con 2021: Making Music! In Emacs?!https://zck.org/bangbangcon2021https://zck.org/bangbangcon202121 May 2021 00:00:00 EST I presented Making Music! In Emacs!? at !!Con 2021.

If you enjoyed this talk, you might appreciate EmacsNYC, a meetup I co-organize.

Abstract

During quarantine, I found myself spending time with an Android app. One of the features this app has is composing looping music. As with many programs, I wondered how much better this feature would be, if only it was inside Emacs.

This talk explains how I made zmusic, my implementation inside Emacs, with detours through Emacs text properties, font rendering, the WAVE file format, and music theory. And hopefully at the end, we’ll have something worth listening to.

Code & Presentation

The presentation can be viewed online, and the source can be found at https://hg.sr.ht/~zck/zmusic/.

I gave this presentation in zpresent, a presentation framework I wrote. The presentation source is available.

WAVE References

  1. http://soundfile.sapp.org/doc/WaveFormat/
  2. http://www.lightlink.com/tjweber/StripWav/WAVE.html
  3. http://www.topherlee.com/software/pcm-tut-wavformat.html

It was an honor to present as part of !!Con. Thanks to the organizers, presenters, and attendees!

]]>
Use vectors in your generative arthttps://zck.org/vectors-in-generative-arthttps://zck.org/vectors-in-generative-art19 May 2021 00:00:00 EST

Quil is a great library to make generative art with. As might be expected for a library that allows for points to be graphed, many functions expect one or more points to be passed to it.

For example, point, vertex, and triangle all take these x and y values. Quad even takes a whopping eight values, representing four points! Working this way, it's easy to do simple things. Most code I've seen works this way, passing two values for a single point.

(q/point 0 100)

But it becomes harder to do more complicated things.

(let [original-x 0      original-y 100      change-in-x 50      change-in-y 25]  (q/line original-x          original-y          (+ original-x change-in-x)          (+ original-y change-in-y)))

It's easy to lose track of which argument is the x value, and which the y. What if instead, we work with vectors?

(defn vector+  "Add together any nonzero number of vectors."  [& vectors]  (reduce #(mapv +                 %1                 %2)          vectors))(let [original-point [0 100]      change [50 25]]  (q/line original-point          (vector+ original-point                   change)))

This is easier to understand. There is some complexity in vector+, but this complexity is hidden from the user of the function. The version that requires points as separate x and y values pushes all the complexity to the top level.

Note that this relies on the line function accepting arguments as points. Line is a rare Quil function – it not only accepts its arguments as separate x, y arguments, but also accepts the points as vectors.

If we want to use Quil functions that don't already take arguments this way, we can wrap them. For example, vertex can be wrapped as follows:

(defn vertex  "A version of quil's vertex that takes a point  as a single argument."  [point]  (apply q/vertex point))

So far we've only discussed simple uses – ones that are easy enough to work with even without using points. Let's look at a more complex algorithm that takes advantage of passing around points: Chaikin curves. This algorithm is a method of taking a series of points and turning it into a smoother curve. You can see the effect below, starting with the algorithm not applied at all on the left shape, one more time on each shape to the right than the previous shape.

Four curves, becoming smoother each time the Chaikin algorithm is applied.

The code to generate this picture is below. The important part is in the function chaikin, which takes a seq of points.

(defn chaikin  "Generate the ORDER-th level Chaikin curve for the control polygon  formed by POINTS.  Note that POINTS is treated as an open polygon; we do not wrap  around from the front to back.  Also note that this function is NOT LAZY. Only pass to it points you will  actually graph.  More information is here:  http://graphics.cs.ucdavis.edu/education/CAGDNotes/Chaikins-Algorithm/Chaikins-Algorithm.html"  [points order]  (loop [points points         order order]    (if (< order 1)      points      (recur (mapcat (fn [p1 p2]                       (list (vector-scale (vector+ (vector-scale p1 3)                                                    p2)                                           0.25)                             (vector-scale (vector+ p1                                                    (vector-scale p2 3))                                           0.25)))                     (butlast points)                     (rest points))             (dec order)))))(defn chaikin-blogpost-draw []  (let [control-points [[50 100]                        [100 400]                        [200 350]                        [200 50]                        [100 200]]        number-of-offsets 4        offset-vector [250 0]]    (q/fill nil)    (dotimes [offset-number number-of-offsets]      (q/begin-shape)      (let [offset (v/scale offset-vector offset-number)]        (doseq [point (v/chaikin (map (partial v/v+ offset) control-points)                                 offset-number)]          (h/vertex point)))      (q/end-shape))))(q/sketch :size [1000 500] :draw chaikin-blogpost-draw)

Imagine what this code would have to look like if we dealt with x and y coordinates separately! Operating on points lets us do operations that would be quite painful to do if we passed coordinates around separately. So use vectors.

Postscript

It helps that Clojure works very nicely with vectors – we don't have to make a separate class to handle points. We can use a vector, and it's easy to create, introspect, and pass around. Thanks, Clojure!

]]>
EmacsConf 2020 talk: WAVEing at Repetitive Repetitive Repetitive Musichttps://zck.org/emacsconf2020https://zck.org/emacsconf202029 Nov 2020 00:00:00 EST I presented WAVEing at Repetitive Repetitive Repetitive Music at EmacsConf 2020. Video can be found at this EmacsConf page.

If you enjoyed my talk, you might appreciate EmacsNYC, a meetup I co-organize.

Abstract

During quarantine, I found myself spending time with an Android app. One of the features this app has is composing music that loops endlessly. As with many things, I wondered how much better this feature would be, if only it was inside Emacs.

This talk explains how I made zmusic, my implementation inside Emacs, with detours through Emacs text properties, font rendering, the WAVE file format, and music theory. And hopefully at the end, we'll have something worth listening to.

zmusic: Code & Presentation

The source can be found at https://hg.sr.ht/~zck/zmusic/.

This presentation was performed in zpresent, a presentation framework I wrote. The presentation source is available.

WAVE References

New Emacs Knowledge!

I got some assistance from the Emacs Stack Exchange.

  • Buttons can highlight more than you want.
  • Saving raw bytes to a file is hard!
  • There was a question about making major modes. I used define-derived-mode to make this mode. It's really useful! For more information, I recorded a talk about making major modes a few years ago, at an EmacsNYC meeting.

It was an honor to present as part of this conference. Thanks to the organizers, presenters, and attendees.

]]>
Reduce your Emacs config (by contributing it upstream)https://zck.org/reduce-your-emacs-confighttps://zck.org/reduce-your-emacs-config04 May 2020 00:00:00 ESTOne programming aphorism is that the less code you have, the fewer places there are for bugs to hide. Bill Gates is quoted as saying "Measuring programming progress by lines of code is like measuring aircraft building progress by weight". So when solving a given problem, it's better to have less code. But wait! Even my Emacs config is over 1400 lines! That's a lot of places bugs could be introduced.

So what are some ways of shrinking code? We might make a general solution, so multiple features can be implemented merely by configuring our powerful framework. Or we might decide to simplify the problem. We might also choose to write in a more expressive language, skipping boilerplate by abstracting away code patterns.

These are all good solutions to having less code. But note that these are all about making there be less code. What if we were selfish? Could we simply make us have less code, and rely on other people doing work for us? The obvious answer is to find a library that implements part or all of the solution. But what good is that? Isn't it more fun to write it ourselves? Let's rule out using libraries, and assume we're doing the enjoyable part of writing all the code ourselves.

A lot of the time we're stuck. However, if we're customizing or extending free software, there's another possible solution: push the code upstream. The total amount of code will stay the same, but the amount of code we have to deal with will decrease. And then we won't have to deal with it anymore; the maintainers of the software we contribute to will!

As a bonus, if we push our code upstream, other people will be able to use it also. And it'll be easier than downloading a dependency of a library our made, because it'll be part of the base software package.

And don't forget about bragging rights.

]]>
An open letter to the two gentlemen wearing MAGA hats at the women's marchhttps://zck.org/maga-hats-womens-marchhttps://zck.org/maga-hats-womens-march04 Feb 2018 00:00:00 ESTTo the two gentlemen wearing Make America Great Again hats at the women's march:

Hi. We met at the Women's March in NYC. When I first saw you, you were in a heated discussion about abortion. It seemed out-of-place, so I went up to talk to you, wanting both to see why you were there and to keep the situation from escalating. After talking to you, I don't understand your reasons for coming, as your stated reasons don't make sense to me.

You said were there to prove something I didn't hear any explicit point you were trying to prove, but rather assorted "free speech is important" mumblings. about free speech, presumably something about how you were being denied it. But I'm not sure what. You were allowed to march; you were allowed to talk: to my eye, you had all the free speech you wanted. In fact, the march itself was free speech writ large! Individual citizens did make their opinions about you known — alternately, some ignored you entirely — but that is their free speech. As far as I can tell, all you proved is that everyone there was exercising free speech.

You said you were there looking for a debate. You'll have to forgive me for not being sure what you wanted to debate: it was hard to hear a consistent point while the two of you switched places several times; the one of you who had been talking to me left mid-conversation to search, with laser-like focus, for the nearest video camera.

You seemed to think that nearly all places are ideal for such debate. I pointed out you attended a march, where the whole point is to have groups of people walk. You said you were looking for a side space to stand to have a debate. I mentioned it would be hard to communicate to more than one or two people at a time, because of the noiseEven without the march, New York City streets are not known for their serene, library-like atmosphere., and people walking by in the cold. Also, why were you surprised people at a march were almost completely uninterested in debate? Nor, either, would they be interested in going swimming. They came for a march, and they wanted to march, not swim or debate.

You said you were against abortion. I didn't hear much of your argument: when you were making it, we hadn't started talking yet, and I could barely hear what you were saying. But I do know that after you talked to a man saying he was a biologist, I heard no more claims that a fetus was an independent life because it has its own blood type.

You said something with your MAGA hats. You seemed surprised that no one talked to you to find out you didn't vote for Trump, but instead Gary Johnson. I'm not sure why you were surprised; I didn't see either of you ask anyone if they agreed with the sign they were holding. The natural assumption is that a person speaking a message agrees with that message. I'm reminded of the xkcd quote: "communicating badly and then acting smug when you're misunderstood is not cleverness". What one wears is a form of communication, especially when one is wearing a slogan. People purchase and wear MAGA hats to send a message. So, to be shocked that people thought you endorse the message that was emblazoned on your head seems — to be charitable — misguided.

And that, I think, is the best-case scenario for your motivations at the march: misguided. You didn't express a coherent point of view, you were looking for a debate in a place not very fit for debate, you made an explicit point about communication that was contradicted by your actions, and that your presence was permitted proved whatever free speech point you were making invalid. I wish I had said this at the march. I'm saying it now.



Thanks to Julia Rittenberg for giving feedback on a draft.

]]>
Testing Emacs code that modifies buffershttps://zck.org/testing-buffer-modifying-emacs-codehttps://zck.org/testing-buffer-modifying-emacs-code02 Oct 2017 00:00:00 EST

2022 Update: I have since made an improved version of the code in this article. This article is still useful to read as motivation for the problem.


I was writing some functions to change variable names from camelCase to snake_case, and back again. (For some reason, Java code uses camelCase, and SQL colmns are named with snake_case) Because this was nontrivial code, I wanted to test it.

If the functions took a string as an argument, and returned the modified value, I'd be able to write some simple tests. These tests would call the function on some strings, and check the return value. But instead, the functions we want to test modify the buffer instead of returning a value. So what can we do to test this code? We could rewrite the functions to be small wrappers around functions that do the "actual work" of changing cases. It would be unfortunate to have to rewrite the code to be able to test it, but at least we'd be able to write some tests.

But even wrapping the functions this way wouldn't be enough! The functions change point, which is not testable by checking the return value from such a wrapped function!

What would I do if I was testing it by hand? I'd insert some text in a buffer, call my function on it to modify the buffer. I'd then examine the text in the buffer. Here's the outline of what I want to do:

In a temp buffer:  insert text  move point to the beginning of the buffer  call the function being tested  return the entire buffer as a string

That maps to emacs lisp code straightforwardly:

(with-temp-buffer  (insert "hi_mom")  (goto-char (point-min))  (camelcase-dwim 1)  (buffer-string))

Great! This code now calls our function under test on a specific input string, and returns the value of the buffer at the end. Let's set it up as an ERT test:

(ert-deftest camelcase-dwim/single-word-from-snake-case ()  (should (equal "hiMom"                 (with-temp-buffer                   (insert "hi_mom")                   (goto-char (point-min))                   (camelcase-dwim 1)                   (buffer-string)))))

But look how repetitive a second test would be!

(ert-deftest camelcase-dwim/two-words-from-snake-case ()  (should (equal "hiMom howAreYou"                 (with-temp-buffer                   (insert "hi_mom how_are_you")                   (goto-char (point-min))                   (camelcase-dwim 2)                   (buffer-string)))))

That's a lot of copied code. Let's write a macro that does this for us:

(defmacro on-temp-buffer (string &rest body)  "Insert STRING into a temp buffer, then run BODY on the temp buffer.Point starts at the beginning of the buffer, and after running BODY,the entire buffer is returned as a string."  (declare (indent 0) (debug t))  `(with-temp-buffer     (insert ,string)     (goto-char (point-min))     ,@body     (buffer-string)))

Now, the test code is much shorter:

(ert-deftest camelcase-dwim/single-word-from-snake-case ()  (should (equal "hiMom"                 (on-temp-buffer                   "hi_mom"                   (camelcase-dwim 1)))))

Awesome, this test is now way easier to read because it only has the logic we care about. But we're not done. Remember that #'camelcase-dwim moves point? I want to make sure point is moved to the right place. So I wrote a similar macro which returns (point) instead of (buffer-string):

(defmacro on-temp-buffer-point (string &rest body)  "Insert STRING into a temp buffer, then run BODY on the temp buffer.Point starts at the beginning of the buffer, and after running BODY,\(point) is returned."  (declare (indent 0) (debug t))  `(with-temp-buffer     (insert ,string)     (goto-char (point-min))     ,@body     (point)))

It can be used as follows:

(ert-deftest camelcase-dwim/basic-snake-case-with-other-words-check-point ()  (should (equal 6                 (on-temp-buffer-point                   "hi_mom and_other stuff"                   (camelcase-dwim 1)))))

So now we have two macros that can be used to test code that modifies an Emacs buffer, without having to change the functions being tested. And that's our goal.

]]>
Presenting zpresent, a presentation framework for Emacshttps://zck.org/zpresenthttps://zck.org/zpresent14 Sep 2017 00:00:00 ESTOnce in a while, I give a presentation. Not too often. You probably do give more than I do. It's not a competition.

Presentations are a pain to make. "Traditional" presentation software requires you to simultaneously create content and determine its layout. So when you're thinking about how to phrase your seventeenth slide about the proper kind of switch to use in your mechanical keyboardCherry MX Green, you also have to use the mouse to drag that text box to the exact right pixel.

It would be easier if a presentation's content was separated from its layout, like HTML does for webpages. Ideally, presentations would be written in a structured, text-based input format. Luckily, in Emacs, there is a very popular structured text format: Org files! But let's put aside Org for now, and pretend it's not a loose end that I added in to call back later.

Many of my presentations involve code. It would be nice, when giving a presentation, to be able to present from inside Emacs, so I can easily switch between the presentation and a code demo, without having to un-fullscreen a window to find Emacs when switching to the demo, and upon going back to the presentation, switching to the presentation program and re-fullscreening it.

So I looked at existing presentation frameworks for Emacs. Some, like org-reveal or the built-in ox-beamer, render a separate presentation, like a reveal.js or LaTeX file that's the presentation. So they fail my goal of presenting inside Emacs.

Others, like org-present and org-tree-slide, present from within Emacs. They look like narrowed Org files, because they are narrowed Org files. That's nice for writing the presentation, but I want the presentation to look more like a traditional one, with a slide header, and nice layouts. epresent is close, but looks like a zoomed-in Org file. meta-presenter is similar, in that it looks like (and is) narrowed Markdown files.

So I wrote zpresent, a presentation framework that presents Org files in the style of a traditional presentation. The input looks like this:

  * A presentation title.:PROPERTIES::type:     title:author:   me!:END:* A regular slide here** Point one!** Point two!** Point four! (fooled you!)

Isn't that nicer? Not only can you ignore layout details, you can also use the power of Emacs and all its powerful commands to edit your presentation.

It's displayed as a "traditional" presentation, with a large title at the top, and some formatting to look good. Here's what it looks like:

An example of a zpresent slide, with headline and nested bullets.

It's still early in the project, but the input format is pretty stable. The project is built on top of org-parser, a library I wrote to parse Org files.

The software repository contains installation instructions.

There were some interesting takeaways from doing this project. I learned that the Org file format is incredibly complicated. For example, you can't add tags or properties to plain lists. I also added a macro and fixed a bug in dash before realizing I didn't actually need to use the macro I added.

Thanks to Karan Sagar for feedback on a draft.

]]>
Move files in Emacshttps://zck.org/emacs-move-filehttps://zck.org/emacs-move-file05 Dec 2016 00:00:00 EST

Emacs's default way to write a file to a different location is #'write-file. This function saves the buffer to a new location, but leaves the old file where it was. But sometimes we want to move a file, so the old file is gone!

There are two built-in functions with similar purpose.

  1. #'rename-file
  2. #'dired-do-rename

Neither of these are great for this use case. The existing functions don't default to the file from the current buffer, so you have to type the existing filename. After calling the function, we're left with a buffer that, when saved, saves to the old location. We don't have a buffer visiting the new file.

So we have to write something! We want something that takes the current buffer, prompts for a new file location, and moves the file there. We can't do the move atomically, so we instead delete the file only when the move was successful.

(defun move-file (new-location)  "Write this file to NEW-LOCATION, and delete the old one."  (interactive (list (expand-file-name                      (if buffer-file-name                          (read-file-name "Move file to: ")                        (read-file-name "Move file to: "                                        default-directory                                        (expand-file-name (file-name-nondirectory (buffer-name))                                                          default-directory))))))  (when (file-exists-p new-location)    (delete-file new-location))  (let ((old-location (expand-file-name (buffer-file-name))))    (write-file new-location t)    (when (and old-location               (file-exists-p new-location)               (not (string-equal old-location new-location)))      (delete-file old-location))))

The code that prompts for a new file location is taken from #'write-file, which we also use to move the file to that new location. We then delete the old file. Because we only delete the old file if it exists, it's safe to use this method even when the file was never originally saved.

You can bind it using bind-key:

(bind-key "C-x C-m" #'move-file)

And then have an easier time managing files in Emacs.

Thanks to u/tashbarg and Toby Cubitt for pointing out bugs in the initial implementation.

]]>
Easily repeat Emacs functionshttps://zck.org/emacs-repeat-emacs-repeathttps://zck.org/emacs-repeat-emacs-repeat11 Sep 2016 00:00:00 EST

Sometimes you want to repeat an Emacs function, even when calling it originally took a few keystrokes. Here's how to make it easily repeatable. Say we have a simple function that inserts "here":

(defun insert-here ()  (interactive)  (insert "here"))

And bind it to C-c h h:

(global-set-key (kbd "C-c h h") #'insert-here)

This works; every time we type C-c h h, we insert "here" into the buffer. But often we want to repeat the command. Although we could use C-x z to repeat the last command, that's still two keypresses, and isn't the easiest thing to press once you've typed C-c h h. So instead, we can make a sparse keymap and in it, set "h" to this command.

(setq insert-here-keymap      (let ((map (make-sparse-keymap)))        (define-key map (kbd "h") #'insert-here)        map))

Now we just need to use this keymap inside #'insert-here. We can't use #'use-local-map, because that will mean we can never insert h again: we'd always call #'insert-here. Instead, we can use #'set-transient-map, which still uses the local keymap, but deactivates the keymap after a single key is pressed.

(defun insert-here ()  (interactive)  (insert "here")  (set-transient-map   insert-here-keymap))

Now, after activating #'insert-here, we can repeat it by pressing h. But if anything else is pressed, the keymap disables. Further presses of h will insert the letter; the keymap is no longer used. So we've accomplished our goal of easily repeating this command with a single keypress.

]]>
balanced delimitershttps://zck.org/delimitershttps://zck.org/delimiters24 Jun 2014 00:00:00 ESTThis week's Coding for Interviews newsletter, as usual, included a challenge. This week's was to parse a string, determining whether all the delimiters (parentheses, curly, and square braces) it contains are balanced.

For example, the string Math.min(3, 7) is balanced, while Math.min(3, )) is not.

Since I'm a big fan of Lisp, I'm writing my solution in Arc, a modern Lisp.

As we all know, Lisp has no iteration, just recursion.

Well, not quite. Although it allows for both techniques, recursion is common in the Lisp community. Let's look at the problem of finding balanced delimiters in strings, and compare recursive and iterative solutions. First, the recursive method:

(def is-balanced (str)     (no (find-unbalanced (coerce str 'cons))))(def find-unbalanced (char-list (o delims (obj #\( #\)                                               #\[ #\]                                               #\{ #\})))     "Returns a list, in order, of all unbalanced delimiters."     (when char-list       (with (cur (car char-list)              unbalanced-to-right (find-unbalanced (cdr char-list)))             (if (mem cur (keys delims))                 (if (is delims.cur                         (car unbalanced-to-right))                     (cdr unbalanced-to-right)                   (cons cur unbalanced-to-right))               (mem cur (vals delims))               (cons cur unbalanced-to-right)               unbalanced-to-right))))

This method takes the first delimiter it finds, and if it's an open one, makes sure it matches the first unmatched one in the rest of the string. We calculate this by recursing further down into the string.

If the delimiter is a close delimiter, then we pass it back to the calling code, so it can be matched further up in the call tree.

At the end, we simply return any unmatched delimiters. If there are none, we know the string is properly balanced.

But how do we know it works? Let's write some unit tests, using my test framework for Arc. The tests are fairly straightforward.

(suite delimiters       empty (assert-t (is-balanced ""))       parens (assert-t (is-balanced "()"))       parens-then-curlies (assert-t (is-balanced "(){}"))       nested-parens-square-curlies (assert-t (is-balanced "([{}])"))       mixed-parens-brackets (assert-nil (is-balanced "([)]"))       open-paren (assert-nil (is-balanced "("))       close-paren (assert-nil (is-balanced ")"))       square-dont-match-curly (assert-nil (is-balanced "([})")))

So now the iterative version.

(def is-balanced (str)     (with (char-list (coerce str 'cons)            delims (obj #\( #\)                        #\[ #\]                        #\{ #\})            unmatched-openings nil)           (errsafe (do (each char char-list                              (if (mem char (keys delims))                                  (push char unmatched-openings)                                (mem char (vals delims))                                (unless (is char                                            (delims (pop unmatched-openings)))                                  (err 'found-it))))                        (no unmatched-openings)))))

We just make a list of opening delimiters we haven't matched yet, and iterate through, removing them when we find a match. If we ever find a close delimiter that doesn't match the most recent open delimiter, we know the string is unbalanced.

There's a little weirdness, because Arc doesn't have a way to return early from a function, so we have to create an error, then catch it with errsafe, which returns nil if an error occurs.

Overall, I prefer the recursive version, but that is largely because of the better control flow -- everything else is a little bit simpler in the iterative version. And even though it's not required by the newsletter prompt, both versions handle strings with characters other than delimiters.

]]>
Winning the #008000 jacket: code golfhttps://zck.org/golfhttps://zck.org/golf19 Aug 2012 00:00:00 ESTMy job recently had a code golf challenge: the shortest code wins. The task was to write k-means: take a set of data and reduce it to k points. There are many algorithms to do this, but the specific algorithm for this challenge was to, until you had few enough data points, find the two closest points and merge them. First, my winning 227-character entry:

(def d(p q)(apply +(map(fn(m n)(expt(- m n)2))p q)))(def m(k s)(if(len> s k)(m k(let(r t)(best(fn(p q)(<(d p.0 p.1)(d q.0 q.1)))(apply join(map[map(fn(l)`(,_,l))(cdr(mem _ s))]s)))(cons(map(fn e avg.e)r t)(rem r(rem t s)))))s))

Ok, that's unreadable. I get it. The code, as I started with it:

(def distance (p1 p2)     (apply +            (map (fn (d1 d2)                     (expt (- d1 d2)                           2))                 p1                 p2)))(def k-means (k points)     (if (len> points               k)         (k-means k                  (collapse-nearest points))       points))(def collapse-nearest (points)     (let (rem1 rem2) (closest points)          (cons (map (fn dimensions                         avg.dimensions)                     rem1                     rem2)                (rem rem1                     (rem rem2                          points)))))(def closest (points)     (best (fn (p1 p2)               (< (distance p1.0 p1.1)                  (distance p2.0 p2.1)))           (cartesian points)))(def cartesian (elements)     (apply join            (map [map (fn (ele) (cons _ ele))                      (cdr (mem _                                elements))]                 elements)))

To get from the readable code to the golfed code, I did some standard minification techniques: making all names one-character, inlining functions, and removing extra whitespace. Nothing too fancy.

The good:

  • Minimal syntax in lisp. less whitespace needed. This leads to incredibly ugly, unreadable, but short code.
  • Arc's intra-symbol syntax. I only used one example: instead of writing (x y) , Arc lets me write x.y . This cuts down on the parentheses, so if the tokens before or after this function call were going to be parentheses anyway, I was able to drop one or two characters each time I used it.
  • Quasiquote replacement lets data objects be constructed concisely.
  • Anonymous functions are a giant win.
  • Arc-specific functions (or lisp ones): best, len>
  • Higher-order functions make the code work for any number of dimensions
  • A repl makes for really simple testing and development.

The bad:

  • Readability, obviously, dropped incredibly. The second-place entry was Python, but it was somewhat readable.
  • Why does avg take a single argument: a list of nums? Seems like it should be variadic.
  • On lists, + isn't join. It creates new conses. This is frustrating, and confusing:
    arc> (def check-cars (join-fun)          (let x (list (list 1))               (is (car (join-fun x))                   (car x))))#<procedure: check-cars>arc> (check-cars +)nilarc> (check-cars join)t
  • Similarly, (mappend f seq) isn't (apply join (map f seq)), when f returns lists.
  • If + is similar to join on lists, why not define (* seq1 seq2) as the cartesian product of the two sequences, when seq1 is a list? It somewhat mirrors +.

notes:

  • You don't have to calculate everything properly, as long as you get the results you want. My distance function doesn't take the square root of the result. Because the distance between two points is only used is to compare two distances, you can compare the squared distances instead. The relationships are the same, which is all that matters.
  • I thought of no simple way to do this but functionally, using recursion. The second place winner, who wrote in Python, approached this imperitively, using mutable state. We actually had to explain our solutions to each other, as the minified versions were not easy to gather the algorithm from. Programming styles can be restrictive.
]]>