Working with the mind, not hands: an example of increasing text editing performance in Emacs

History


I almost finished one project and, as it always happens, at the last moment it was required to make massive routine changes.

It was a Bash script to automate the build process on various Unix and, the reality is that there was nothing in common between my environment and the build server environment.

The conclusion was one: it was necessary to use the absolute paths to the utilities that were found in the script. For this, I decided to use variables, as in the GNU Autoconf : “RM=/usr/local/bin/rm”and “${RM} -vf foo”.

The work is almost done, but I have 3 such scripts that look very similar and I absolutely do not want to do these replacements with my hands ... so I tried to make the version of `replace-string ' in Emacs- new * scratch * the buffer is just for my problem:

(defun foo ()
  (interactive)
  (let ((begin (region-beginning))
	(end   (region-end)))
    (mapcar #'(lambda (p)
		(replace-string (format "%s " (cadr p))
				(format "${%s} " (car p))
				nil begin end))
	    '((GNUTAR tar)
	      (GUNZIP gunzip)
	      (GZIP gzip)
	      (GMAKE gmake)
	      (AUTORECONF autoreconf)
	      (MKDIR mkdir)
	      (ECHO echo)
              (CP cp)
	      (FIND find)
	      (RM rm)
	      (TEST test)
	      (LN ln)))))

And it's all!

A little more detail what kind of code


This is the `foo ' function , which can be called interactively in the editor, i.e. while editing text, and not just from the body of other functions. It extends the action of the `replace-string ' function by calling it for each element in the list:
             ((GNUTAR tar)
	      (GUNZIP gunzip)
	      (GZIP gzip)
	      (GMAKE gmake)
	      (AUTORECONF autoreconf)
	      (MKDIR mkdir)
	      (ECHO echo)
              (CP cp)
	      (FIND find)
	      (RM rm)
	      (TEST test)
	      (LN ln))

As a result, replacing the second value of each element found in the text with the first (for example "tar", "GNUTAR").

At the beginning of its execution, the `foo ' function determines the boundaries of the selected region in which it should make replacements: these are the calls to` region-beginning' and `region-end ' .

Then, the `mapcar ' function is called, which calls the lambda (p) closure function for each element of the list.

The function of the closure function is to parse the p variable into components and call the replace-string function to replace it in the text.

Epilogue


I note that the functions of the `map ' family can operate on an arbitrary number of lists and, at first glance, it seems that instead of a list of lists, two spikes of values ​​could be used: (GNUTAR GUNZIP GZIP ...)and (tar gunzip gzip ...), but such an organization of the data structure is obviously more complicated due to implicit relationships between the two lists, while in the proposed embodiment, such a relationship does not go beyond the scope of the sublist.

conclusions


The considered function is a one-time design designed to solve the problem that appeared before one person. The author sees the universalization of this design as a pointless exercise. The purpose of this post was to show the simplicity and ease of programming a tool (Emacs editor) that a person can use if he wants to work with his mind, not his hands.

Also popular now: