Content AND Presentation

2022-01-17 Making code snippets in Org-mode easier to type

From time to time people tend to discuss the Org markup – some people want to extend it in one way or another, some people want to make it more Markdown-ish. I tend to agree that the selection of the tilde (~) to denote code is a bit inferior than Markdown’s choice of the backtick (`). But keep in mind this: I don’t have a problem with looking at my Org file and seeing (lots of) tildes. After all, font-lock does a good job of telling me that this is code. I have a problem with typing these tildes, since they require me pressing the shift key – and if I have a lot of small code snippets, this is not very comfortable. Add to this the fact that I happen to write in Markdown pretty often (when I use Markdown-based tools, like Slack or Jira), and I started wondering: why couldn’t I press the backtick in Org-mode to type a tilde (and vice versa so that I don’t lose the ability to type a backtick)?

Now, this is probably easy to accomplish using xmodmap. But I am an Emacs user, so where’s the fun in that? Of course I don’t want to bind a command with some simplistic code like (insert "”)~ to the backtick, since I could lose things like tables aligning automatically or speed keys (which I wouldn’t regret since I don’t use them – but maybe I’ll will one day?). Well, by default both backtick and tilde are bound to org-self-insert-command in Org-mode. It would be best if my command could call that but trick it to think that another key was pressed. It turns out that this can be done by setting the variable last-command-event. (And I can’t help but mention that this variable and an example of its use are discussed in one of the chapters of my book on Elisp!) So, the most basic version of swapping the meaning of tilde and backtick may look like this:

(defun org-insert-backtick ()
  "Insert a backtick using `org-self-insert-command'."
  (setq last-command-event ?`)
  (call-interactively #'org-self-insert-command))

(defun org-insert-tilde ()
  "Insert a tilde using `org-self-insert-command'."
  (setq last-command-event ?~)
  (call-interactively #'org-self-insert-command))

(define-key org-mode-map (kbd "`") #'org-insert-tilde)
(define-key org-mode-map (kbd "~") #'org-insert-backtick)

Now, the two commands defined above are so similar that I could write a macro to define them:

(defmacro define-org-insert-whatever (name character)
  "Make the function `org-insert-NAME' insert CHARACTER."
  `(defun ,(intern (concat "org-insert-" name)) ()
     ,(format "Insert a %s using `org-self-insert-command'." name)
     (setq last-command-event ,character)
     (call-interactively #'org-self-insert-command)))

This seems a good idea on paper, but has a significant drawback – when looking up a function generated this way (with C-h C-f), we don’t get the link to the source of the function. So in this case I prefer to type the defun​s by hand. Also, in a moment I’m going to change the definition of org-insert-backtick anyway.

I am not sure how long this contraption is going to survive in my init file, since this is pretty unorthodox and I may get tripped by this more than one time (muscle memory is a thing!). But I’m going to try to stick with it, because it’s cool, and I need the tilde character pretty often when writing this blog, for instance. Also, having coded the above, I could get really fancy and do this:

(defvar-local org-insert-tilde-language nil
  "Default language name in the current Org file.
If nil, `org-insert-tilde' after 2 tildes inserts an \"example\"
block.  If a string, it inserts a \"src\" block with the given
language name.")

(defun org-insert-tilde ()
  "Insert a tilde using `org-self-insert-command'."
  (if (string= (buffer-substring-no-properties (- (point) 3) (point))
      (progn (delete-char -2)
	     (if org-insert-tilde-language
		 (insert (format "#+begin_src %s\n#+end_src"
	       (insert "#+begin_example\n#+end_example"))
	     (forward-line -1)
	     (if (string= org-insert-tilde-language "")
		 (move-end-of-line nil)
    (setq last-command-event ?~)
    (call-interactively #'org-self-insert-command)))

How cool is that? Now when I press the backtick three times when at the beginning of the line (like what I’d do when typing in Markdown to create a code block), I get an example block (or a source code block in any language defined by the org-insert-tilde-language variable, which can be set as a buffer-local variable). If that variable is an empty string, I can fill in the language; otherwise, I can edit the example or source block straight away. Also, this variable is defined with defvar-local so that it is automatically buffer-local. (Also, you might want to set it up as a file variable.)

Now this is clearly not something for everyone. But note that – as usual – it is a perfect example of Emacs malleability. Coding this took me about 15 minutes, and even if it’s not perfect or could break in some circumstances (which can probably happen, given the level of complexity of Emacs and the plethora of its existing packages – I can’t possibly predict the potential interactions between them!), I could just dive back into the code and fix any issues when they appear.

And again, let me say that this only takes 15 minutes of coding when you are pretty well-versed with Emacs standard library. And becoming pretty well-versed with Emacs standard library is not that difficult – you just have to code in Elisp enough to learn it. (Well, there are some resources that can help with that… Just saying! ;-) )

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode

Comments on this page

2022-01-10 Simple tmux scripting revisited

Some time ago I wrote about my (very simple) tmux script. Since then I started to like tmux even more, and in fact I tend to create a similar script for every major project I work on. Last time, however, I noted how the sleep part is very fragile (and less than elegant). Since then I realized that I do not need any advanced scripting to run command Y in tmux window B when command X in window A finishes its job. In fact, this is very simple, and I’m ashamed I didn’t think about it earlier. The trick is to combine command X with a tmux invocation telling tmux to run command Y. So, here would be the script from the previous post updated to use this technique:

tmux new -s work -d
tmux rename-window -t work logs
tmux send-keys -t work 'cd $BASE_DIR && vagrant up && tmux send-keys -t work:vm "cd $BASE_DIR && vagrant ssh" C-m && vagrant ssh' C-m 'pm2 log' C-m
tmux new-window -t work
tmux rename-window -t work vm
tmux new-window -t work
tmux rename-window -t work term
tmux send-keys -t work 'cd $BASE_DIR && git pull' C-m
tmux attach -t work

This way the second window “waits” with logging in tho the VM until it has properly started. Notice how we use the session:window syntax to send the keys to the correct window.

I still consider moving all that to Emacs. In fact, several Eshell windows and a saved window configuration might work in a very similar way. I guess I really need to warm to Eshell more – it has a lot of cool features I could really use. (One potential issue I have with Eshell is using it over ssh. Yes, I know I can use it with TRAMP, but I am a bit paranoid about Emacs somehow saving some data from the other end, like in some cache or a similar thing, and since I sometimes deal with rather sensitive data on a production server, it would be a very bad thing to happen. I’ll probably dive deeper into this issue one day…)

CategoryEnglish, CategoryBlog, CategoryEmacs

Comments on this page

2022-01-03 The Emacs Lisp book - looking back and into the future

The time has come to make a short summary about the Hacking your way around in Emacs book I’ve been writing last year. The book is finished (sort of – we’ll get to that in a moment), and I learned a few things from the experience.

First of all, I was dumbfounded by the sheer amount of people who bought the book. I was hoping for 100–120 copies sold, and over 300 people bought the book. That was a very nice surprise. (I think that being featured on Hacker News helped quite a lot.)

I was also pleasantly surprised that only two people so far decided to use Leanpub’s refund feature and returned the book, getting their money back. One of them wrote that the book was “too verbose”. Well. You can’t satisfy everybody. Actually, I consider this a valid criticism – some people prefer a more concise style. That’s ok – it’s just that I’m not one of those people, and I also tend to write in a more, let’s say, flowery style. (I sometimes try to fight this tendency, but it’s a deeply ingrained one.)

I also got other remarks. One was that the table of contents is a bit cryptic, and I should have a better description of the contents themselves on the book website. This is a very good point, and I amended the website to accommodate it – I’ll be working on the ToC soon, too. Another one was that the first, introductory chapter (the one where we move lines around) is boring. Well, it may be true. It was not exactly designed to be fascinating, you know – it’s purpose is to teach some Elisp and showcase my writing style so that you can decide if you want to buy the whole book. I agree that it would be nicer if the book started with a bang, but I couldn’t really think of any other idea for an easy introductory chapter. And I assume that if you are going to learn Elisp, you are already pretty motivated, so you don’t need an Alfred-Hitchcock-level captivating story to get involved.

I was also asked a couple of times if I’m going to prepare a paper version. The answer is yes, but that will not happen very soon – I plan to work on this in late 2022 or early 2023.

As for my other plans: now that the dust has settled, I thought about it and concluded that I would like to expand the book a bit. I haven’t decided yet what I’m going to add, but I think 2 or 3 chapters could be the right amount of material. As for what exactly it is going to be… well, we’ll see. I have some ideas, but I still haven’t decided for sure.

Anyway, even if I plan to put some more work into the book (and that’s why I still hesitate to call it “finished” – it would be more accurate to call it “v1.0”), the project so far turned out to be a success. I think this confirms the general idea that writing a book for a clearly defined audience is the way to go. In this case, I tried to write a book I wanted to have when I was learning Elisp almost ten years ago – something to be read after Robert J. Chassell’s An introduction to programming in Emacs Lisp.

Also, I have ideas for more books – I really like writing, and I’d like to practice it more. Hopefully, time will come for another writing project of mine in a few months. Meanwhile, I’m very proud of Hacking your way around in Emacs as it is.

CategoryBlog, CategoryEnglish, CategoryEmacs, CategoryEmacsBook

Comments on this page


CategoryEnglish, CategoryBlog