Skip to content

Swapping quote symbols in Emacs with parse-partial-sexp

Aug 26 14
by mickey

Ever wonder how Emacs *knows* that the point is next to a balanced expression like a bracket or a string? That kill-sexp or up-list knows how to kill the balanced expression at point or move up one level in a nested set of brackets, in just about any major mode out there?

At a higher level the mode author may choose to write his own parsing routines for handling balanced expressions in that particular mode; but unless your mode’s very special (LaTeX comes to mind) most choose to rely on Emacs’s own ability to parse certain recurring concepts that appear in most major modes — be it something as simple as text-mode or as complicated as a full-blown major mode. A few modes may augment this basic parser with additional functionality, but for a lot of languages (particularly C-like languages) — it’s more than enough.

The secret is parse-partial-sexp and syntax-ppss. The latter function is still an undocumented snippet in syntax.el and yet it’s a first-class citizen used in hundreds of places all over the Emacs elisp source code.

So what makes a barely-kept secret to mode writers such an interesting function? It possesses the unique ability to parse and understand common syntactic elements: comments; strings; and balanced expressions, like brackets. It uses Emacs’s syntax table, a giant key-value table used by modes and some commands to tell Emacs how it should treat alphabetical characters and special characters like [ and ".

So the good news is all that information's already taken care of for you by the mode authors: all you have to do is think of instances where you may want to edit or move by syntax.

So let's say you want to switch the quote symbols in Python from single to double-quote or vice versa:

We want to run one command that turns 'Hello█ World' into "Hello█ World" where █ is the point.

Because syntax-ppss understands the basics of our major mode's language syntax this is rather easy to do.

Let's write a function that determines if point is in a string or not (actually, such a function already exists in thingatpt.el called in-string-p):

Here I'm using syntax-ppss-context, a helper function that can return three different states: comment, string, or nil.

If you eval M-: (point-in-string-p (point)) you can test if the point in the active buffer is in a string or not.

Making a function that does the same for comments is trivial: replace string with comment and bob's your uncle.

The next piece of the puzzle is that we need to be able to move out of a string if we're in one or throw an error if we are not. We need to "move out" of it as we want to replace the quotes surrounding a string; the easiest way to do this reliably is to find the bounds of the string: the beginning and end.

This function is marked as interactive so it can be called through M-x, bound to a key, used in macros, and so forth. Then we test if we're not in a string: if we are not, we bail out with an error. You could remove that check and rely on the while loop failing the initial condition but then you wouldn't get an error message that would propagate.

The while loop itself is simple: as long as we're in a string go forward by negative one characters (that's the elisp convention for going backwards.) And finally we return the location of point.

The next step is to go to the end of the string. We can do that in two ways: extend beginning-of-string so it's generic and will take a direction: -1 for backwards and 1 for forwards. The other is to use Emacs's own set of commands that work on s-expressions, like forward-sexp (C-M-f.)

The latter is easier (and the former left as an exercise to the reader.) What we need now are the points immediately before and after each quote symbol before we start changing things.

If we change the first quote symbol at the beginning of the string then we are left with invalid syntax and Emacs's parse-partial-sexp cannot reconcile the two mismatched quotes when we call forward-sexp. So we have to store the positions first, and then change the quotes.

The other thing we have to remember is to move the point back to the original position where the user called the command; not doing so is considered bad form in elisp land: you should not move the point unless the point (ha) of the command is to move around the buffer.

This interactive command will swap the quotes of the string point is in. It starts out by recording the position of the beginning and end of the string. If we're not in a string, the command will exit with the error propagated from the beginning-of-string command above.

Next we go to the beginning of the string and we check what the replacement character should be and delete the next character and insert our replacement character. The same is repeated for the end of the string. And finally because we save-excursion at the beginning of the command the point is placed back at its original position.

There are a few obvious improvements: the delete/insertion code could be abstracted into a letf-bound function - but that seems like overkill. Another optimization is supporting triple quotes by using the looking-at function and passing it a regular expression that matches single or double quotes, in singles or triples, and replacing the match with the replacement character.

But the function works. And it could easily work for other modes with interchangeable quotes -- or even other paired expressions, like brackets. In fact, making it work with brackets is easier as the built-in command up-list (C-M-u) will go to the beginning of a balanced pair and forward-sexp will go to the end of the balanced pair at point.

Thanks to a little-known feature of Emacs's syntax parser you can make some simple assumptions about the text in a buffer and act on it in a structured manner.

dirswitch.el: a fish shell-style directory switcher for shell-mode

Aug 17 14
by mickey

A friend of mine showed me Fish Shell, a shell replacement for Mac and Linux. One of its coolest features was a “quick directory switcher” that lets you jump to directories you’ve previously visited in that session.

Feeling left out I decided to write dirswitch.el, a directory switcher for M-x shell, Emacs’s built-in shell mode (see Running shells in Emacs: an Overview.)

Like Shell’s M-r history search functionality (which works much like isearch) dirswitch.el will record directories you visit and let you rapidly switch between them by pressing C-M-n and C-M-p.

It’s still a rough prototype but it’s a hallmark example of what a few hours of Emacs hacking can accomplish.

You can get it from my Github and it’ll probably appear in a package manager near you soon.

Displaying and Interacting with processes using Proced

Jul 8 14
by mickey

If you’re a regular user of the commandline tools top or ps then I have good news for you: there’s an Emacs command that does that and it works on Windows too!

The command is M-x proced and it is modelled on M-x dired (but it is not built on top of dired) and it does shadow most of the common navigational aids: n and p move down and up and g refreshes the buffer, for instance.

It’s also feature rich; by combining the utility of ps with the sortable, columnized and interactive system of top you get the best of both worlds.

What I like about it is that it’s a buffer like any other in Emacs. So if you’re keeping your eye on a handful of processes you can use highlight-phrase to highlight the strings you want to visually separate from the rest. It is also, in true Emacs tradition, very customizable — but I’ll get to that a bit later.

Marking, Sorting, Filtering and Formatting Columns

By default you will be given the short formatting but you can change the number of displayed columns by typing F. You’ll be shown a prompt where you can select from short, medium, long and verbose.

You can also change the filtering — which defaults to all — by pressing f. Like the formatting key above you are given a list of common filter types. Furthermore you can filter by any of the visible columns by moving your point to it and pressing RET. It will incrementally filter so you can repeatedly filter as much as you like — this is a very handy feature. Refreshing the buffer with g does not reset it: you must change your filter with f.

Like dired you can mark processes with both d and m (they do the same thing) and unmark with backspace and u. You can mark and unmark all processes with M and U. And finally you can then filter the marked processes with o.

There are some specialty mark commands as well. The command t will invert your marks and C and P will mark the children or parents of the process point is on.

Finally you can sort by columns as well. All the sort commands are bound to M-x proced-sort-xxx and to the prefix menu s:

Command Description
s c Sort by CPU %
s m Sort by Memory %
s p Sort by PID
s s Sort by Start Time
s t Sort by CPU Time
s u Sort by User
s S Sort by other column

If you want to sort by a column not bound to a key you must use s S where you are then prompted for the name of a column to sort by.

Sending Signals and Interacting with processes

Unsurprisingly sending POSIX signals is fully supported by Emacs. This is done using the Elisp function signal-process. Because of that all signals are sent using the uid of the Emacs process proced is running in. Conceivably proced could be changed to call out to userland command kill (using an external command is supported) and, by combining it with TRAMP for sudo elevation it could kill processes owned by other users. Sadly that functionality does not currently exist but abusing the default-directory variable might work.

To send a signal mark the processes you want to signal, or alternatively put your point on the target process, and press k or x. You will be shown a list of target processes and you can optionally change the default suggestion of TERM to something else.

When the signal(s) have been sent you can review the log by pressing ?.

As of Emacs 24.3 you can also renice a command by pressing r.

Understanding & Customizing Proced’s Internals

Proced is very flexible and it also supports the customize interface. You can access this inferface by typing M-x customize-group proced RET.

Proced will use the Elisp function list-system-processes to retrieve all the known PIDs and then call process-attributes on each one of them to fetch the process details. The good news is that Proced does not parse the output of ps or /proc directly but relies on Emacs’s compatibility layer to make sense of everything: this also means it works rather well on Windows.

Proced can auto update the display and you can enable this for a Proced buffer by running the command proced-toggle-auto-update and it will update every proced-auto-update-interval which is by default 5 seconds.

To make Proced auto update by default you must add a hook:

You are free to customize other settings in this mode hook in much the same way you would other mode hook functions.

If you’re really serious about tweaking the way the columns are displayed you can try your hand at editing the alist variable proced-grammar-alist. It controls how sorting, justification and string formatting works for each of the process attributes returned by process-attributes.

You can also alter the default Proced filter by changing proced-filter from user to something else. Creating your own filter is also possible by adding to the proced-filter-alist; in fact this functionality lets you do rather complex things such as calling a custom function for every process attribute.

The default sort and sort order (descending or ascending) is governed by proced-sort and proced-descent respectively.

There are many more customizable options and the author of Proced, Roland Winkler, has done a great job ensuring they’re accessible from Emacs’s customize interface.

It goes without saying that Proced is a both feature rich and customizable. I think it’s a very capable replacement for most ps and top use cases, but like so features in Emacs almost nobody has heard of it.