Opening All Files in a Git Commit

Sometimes even Linux crashes, or a machine loses power, in which case applications lose their history.

This has been an annoyance for me with Emacs and a project that I’m working on that is version controlled with Git, or perhaps I just want to open all of the files in a commit so that they are the most recent in my list of open files in Emacs.

Finally I’ve devised a one line solution, as is noted below.

The first step is to get a list of files from the most recent Git commit, with the output being only the file names — no commit message, author, committer, etc.. Easy enough, where --pretty=format: means “write no commit summary output”:

% git log --git log --name-only --pretty=format: -1

This will be fed into the command to open a file in Emacs, which in my case is function named ec. This is Z shell, but should work for Bash.

ec () {
    for i in $*
    do
        emacsclient --no-wait $i
    done
}

Why a function and not an alias? Because evidently emacsclient only takes one file name as an argument, so it needs to be called once for each file.

Since ec is a function (and the same restriction applies to aliases as well), it cannot be a command executed by xargs, which would have been:

% git log --name-only --pretty=format: -1 | xargs ec

which produces the message “xargs: ec: No such file or directory”.

The fix is to read each line into a variable, then run the function against it. Voila:

% git log --name-only --pretty=format: -1 | while read -r i; do ec $i; done

More of my Z shell blatherings are over here.

Advertisements

Emacs Find of the Day: Repeating Commands

One thing that I love about Emacs is that even after 20 years, I’m finding new (old, in actuality) functionality that makes my life better.

Today’s example is repeat-complex-command, which is normally bound to ctrl-x ESC ESC, as noted on the emacs wiki. The problem in my world is that I’m also using CUA mode, from the ergoemacs library, which redefines ctrl-x to do cuts (as in cut, copy, paste).

Normally that doesn’t cause an issue, since if you don’t have a region marked, then ctrl-x is apparently ignored by ergoemacs and is delegated to the default behavior, in which case ctrl-x ESC ESC brings up the previous command in the echo area, ready to be edited.

However, what has arisen as a nuisance in my experience is when I’ve done a search and replace in one region, then want to do a similar but not identical search and replace in a different region, such as renaming variables in two methods.

Normally I’d mark the first method, run search and replace (query-replace or query-replace-regexp), then go to the second method and mark it. At that point I’d like to bring up the previous search-and-replace and modify the command, but when I hit ctrl-x, the currently-marked region (the second method in this example) is cut, per behavior from ergoemacs.

The fix is to map a different key, in my case alt-j alt-j (the mnemonic being that the keys repeat) mapped to repeat-complex-command, per this snippet from my .emacs file(s):

(define-key global-map (kbd "M-j") jep:keymap)
(define-key global-map (kbd "C-j") jep:keymap)

;; CUA settings muck up ctrl-x, so use an alternative, alt-j alt-j:
(define-key jep:keymap (kbd "M-j") 'repeat-complex-command)

Yes, I map both alt-j and ctrl-j as equivalent keys that define my keymap, making it simpler when I have shortcuts that are prefixed with alt- and ctrl-. So alt-j alt-j flows better, as does ctrl-j ctrl-l (which inserts logging statements, if you’re wondering).

All of this is available at my github repository.

But wait — there’s more: the second nugget of the day is that after running repeat-complex-command, the echo area will display the previous command, of course. But then running alt-p will bring up the command prior to that, and alt-p the command prior to that one, etc. On the other hand, and in the opposite direction, alt-n moves forward through the list of commands.

I hope this helps, and I plan to post more about Emacs and what I find therein.

Emacs and colors being reset

I ran into this today, and couldn’t find a quick answer online.

I was updating yasnippet to the current release, and there was an error on startup about dropdown-list.el not be able to be found. That resulted in Emacs aborting the startup process before it reached the settings in my .emacs file that define the color settings.

So Emacs initialized with the default colors (dark on light), whereas my custom settings are light on dark. When I then exited Emacs, it saved the .emacs.desktop file, which I’d thought was just the list of files. However, it also contains the color settings, so after I’d worked around the yasnippet issue, and started Emacs again, it used the default color settings (from the loaded ~/.emacs.desktop file) instead of mine in .emacs.

The fix was to remove the line that begins with “(setq desktop-saved-frameset”, exit Emacs and start it again, in which case the color settings will be loaded from ~/.emacs instead. The next time Emacs is exited (or just desktop-save is run), then the color line in ~/.emacs.desktop will be updated.

This is probably quite an edge case, but I thought perhaps others might run into this issue. I hope this helps.

Fakir 0.0.1 released

The initial version of Fakir has been released.

This gem is somewhat small, but contains some functionality that I’ve needed in various projects, such as getting a random element from an array (thus Fakir::Array#rand), and getting non-repeating random numbers, i.e. where [1, 1, 1, 2, 2] is actually random, but doesn’t look random, in the same way that [heads, heads, tails, tails] looks less random than [heads, tails, tails, heads].

Fakir::Random#rand goes even beyond that, with support for a “window” in which a number will not be repeated. Thus with a window of 3, a number will not be repeated within 3 invocations of rand.

This gem was developed for seeding Cabin Notebook, and I hope it’s of beneficial use for others.

Cabin Notebook and Fakir

After postponing for years I’ve been working on a website that I haven’t found the equivalent of, Cabin Notebook, which is currently populated (seeded) only with random data.

I’ve been using the excellent Faker Ruby gem, but found its random data to be … too random. That is, I didn’t want truly repeating random data, such as its wide variety of prefix+first+middle+last+suffix names and phone number formats (“Dr. Millie Beatrice Houndhouse III”, “(812)-555-1213” and “1-312-555-9696”), and having the same random number be used repeatedly (such as subsequent labels of “Photo #2”, annotating different photos). Fakir will also support a more flexible version of Array#rand, so that a random element will not be returned within N invocations of that method.

So I’ve created the fakir gem, which supports data that are not quite so random. It’s in the beginning stages, but I plan to have it soon be fully-featured enough to seed the data at Cabin Notebook.

New Z shell blog

I’ve started a blog exclusively about the astonishingly powerful Z shell.

Check it out here: Focus on Zsh.

The goal is to find some of the more interesting and complex examples of Zsh code, and to break them down, explaining them line by line. Despite having worked with Zsh for many years (over a decade), I consider that I’ve barely scratched the surface of what it can do, and, not finding many instructive Zsh resources, have decide to create one.

Please take a look, and I look forward to your feedback.

A for Alias

In Zsh (and other shells), aliases may be the most important feature for increased productivity.

A simple rule is this: the more often you run a command, the shorter it should be. I’ve written about this before, in Efficient Way to Improve Console Productivity.

I have a number of one-character aliases:

G='| glark'
H='| head'
L='| less'
M='| more'
S='| sort'
T='| tail'
a=alias
c=clear
h='history -5000'
l='ls -CF'
t=cat

I’ll write later about those nifty uppercase ones (and yes, there is the alias “a” for “alias”, but for now, I’ll just show them with examples:

alias G -g '^.='

That was the command that I ran to generate the list above. It expands to “alias | glark -g ‘^.='”.

find src -type d S

That finds all directories and pipes them to sort.

There are three “families” of commands that I run the most often:

  • diff – diff files
  • eye – look at/in files on the command line
  • find – list all files/directories matching a pattern
  • open – open files in editor, browser
  • search – look in files

So I have been writing one-character scripts/functions (in Bash) for each of the above, where the script understands context as well as the targets.

For example, “s pluralize” run from a directory that contains a “Rakefile” will expand to search (using glark) only for Ruby files.

e program.tar.gz” is the equivalent of “tar ztvf program.tar.gz“, and “e program.zip” lists the zip file, with entries sorted by name.

d dir1 dir2” runs a recursive diff on the directories, and “d path/to/file ../dir2” will diff “path/to/file” against “../dir2/path/to/file”, if the latter file exists. I do this to avoid the tedious repetition of comparing one code base to another (such as two branches, when merging them): “diff path/to/file1 ../dir2/path/to/file1“, “diff path/to/file2 ../dir2/path/to/file2“, etc.

Although this project is in its early stage, and the output is still rough (i.e., containing debugging output), it already has been quite useful, so I thought I would share.

The project is at Github here.

Cost of Meet(ing)

I’ve long been frustrated that meetings are not quantified, where the cost of the meeting is calculated based on the wages of those in the meeting. With that data, it would be more obvious to determine that cost/benefit of the meeting.

Some back-of-the-envelope calculations here. For four people making an average salary of $100,000 (I’m using programmer gross salaries, including benefits and vacation), a 30-minute meeting would run $96. For twelve people for two hours: $769. Twenty people for two eight-hour days (for example, training): $15,385.

Since I’ve been trying to spin up my web skills I slapped together a site that acts a bit like a timer for a meeting. It’s built on Rails, yet uses little of the framework, other than some of the JavaScript libraries and routing.

Please check it out: costofmeet.org

Rails testing and Emacs mode line

I’ve been diving/digging into the oh-so-excellent Rails Tutorial, by Michael Hartl, and am into chapter 3, where testing begins.

Imagine my surprise — go ahead, imagine it — when my Emacs mode line changed color.

Originally:

modeline_original

And when I ran “bundle exec rake test”, it succeeded with:

modeline_success

Then changing the test code to fail, after running “bundle exec rake test” again:

modeline_failed

Tracking down this code, I found that the guard-notiffany gem was doing this behavior, sending a change to the Emacs mode line via emacsclient, with this bit of code in lib/notiffany/notifier/emacs.rb:

        def notify(color, bgcolor)
          elisp = <<-EOF.gsub(/\s+/, " ").strip
            (set-face-attribute 'mode-line nil
                 :background "#{bgcolor}"
                 :foreground "#{color}")
          EOF
          emacs_eval(elisp)
        end

The issue there was that it just changes the mode line “permanently”. I’d prefer that the mode line colors change for a moment, then time out and revert to their previous settings.

I wrote a bit of code to do this, and modified lib/notiffany/notifier/emacs.rb locally, but there is a pending pull request that has a better implementation.

However, my hack is:

        def notify(color, bgcolor)
          elisp  = "(let ((orig-bg (face-attribute 'mode-line :background))"
          elisp << "      (orig-fg (face-attribute 'mode-line :foreground)))"
          elisp << "     (set-face-attribute 'mode-line nil"
          elisp << "                         :background \"#{bgcolor}\""
          elisp << "                         :foreground \"#{color}\")"
          elisp << "     (sit-for 3)"
          elisp << "     (set-face-attribute 'mode-line nil"
          elisp << "                         :background orig-bg"
          elisp << "                         :foreground orig-fg))"
          emacs_eval(elisp)
        end

The sit-for keeps the mode line as red or green for 3 seconds or when there is Emacs input. I prefer that, to clear the mode line more quickly, since I find the bright color distracting.

Adding Groovy Emacs Mode

I’ve been doing a lot of Gradle/Groovy work lately, and have been using Russel’s Groovy Emacs Mode.

That page provides the documentation for the case where you’re going to put all the *.el files into ~/.emacs.d. However, to keep things nice and organized I put third-party code into a vendor directory under ~/.emacs.d/lisp.

So for the Groovy mode, I added ~/.emacs.d/lisp/vendor/groovy-mode, extracted Russell’s tarball into that, and added these lines to my jep-groovy.el file:

;;; use groovy-mode when file ends in .groovy or has #!/bin/groovy at start
(add-to-list 'load-path "~/.emacs.d/lisp/vendor/groovy-mode")
(autoload 'groovy-mode "groovy-mode" "Major mode for editing Groovy code." t)
(add-to-list 'auto-mode-alist '("\.groovy$" . groovy-mode))
(add-to-list 'auto-mode-alist '("\.gradle$" . groovy-mode))
(add-to-list 'interpreter-mode-alist '("groovy" . groovy-mode))

;;; make Groovy mode electric by default.
(add-hook 'groovy-mode-hook
          '(lambda ()
             (require 'groovy-electric)
             (groovy-electric-mode)))