Tuesday, August 16, 2011

Toggle Airport power from emacs using shell commands

I can usually work for relatively long periods of time without needing the internet, or needing it only sporadically, and mostly while using emacs to edit various kinds of text files.  While I'm doing this, I usually turn off power to the Airport wireless radio on my MacBook Pro to save battery power, then turn it on only when I need it.

Using emacs trains you not to use the mouse unless absolutely necessary, and the small bit of time and effort required to turn the Airport off and on from the menu bar, added up over time, was sort of bothering me.  So, given sufficient desire to procrastinate, I found a way to toggle power to my Airport wireless radio from within emacs.

The first step is to write a shell script to do the toggling (see below).  After a bit of searching, I found the "networksetup" command in the discussion attached to this Macworld hint.  The trick is to use

networksetup -getairportpower en1 | cut -d : -f 2


to get the status and then

networksetup -setairportpower en1 Off


to turn it off, or "On" to turn it back on.


The second step was to insert it into my .emacs.el as a custom function with a key binding.  This was pretty straightforward and the code is in the comments in the shell script below.  The only potential sticky point is to make sure to declare the function as interactive so that it can be bound to a key.


#!/bin/bash

# toggle-airport
#
# Toggles OS X airport power on or off.  dan.t.swain@gmail.com 8/14/11
#
# I built this to be used within emacs.  I bound it to C-c a with the
# following in my .emacs.el (obviously you need to change the path
# for your own use):
#
#  (defun dts-toggle-airport ()
#    (interactive)
#    (shell-command "~/bin/toggle-airport")
#    )
#  (global-set-key (kbd "\C-c a") 'dts-toggle-airport)
#
# Commands gleaned from the following mac hints discussion (near the bottom):
#   http://hints.macworld.com/article.php?story=20070728102702656
#  

# get the current status, this will look like "AirPort Power (en1): Off"
#  so by cutting at the ':' and taking everything after that
#  we get " On" or " Off"
CURRENT_STATUS=`networksetup -getairportpower en1 | cut -d : -f 2`

# determine the new status from the old status - note the leading whitespace
if [[ "$CURRENT_STATUS" == " On" ]]
then
  NEW_STATUS="Off"
else
  NEW_STATUS="On"
fi

# set the new power status
networksetup -setairportpower en1 $NEW_STATUS
# display the results by querying the device again
networksetup -getairportpower en1

Monday, April 4, 2011

2D Matlab Plot With A Triangular Domain

I needed to generate a plot in Matlab for data over a triangular domain.  It took quite a lot of googling to find the answer, which ended up being relatively simple, so I thought I'd post the solution here.

The main trick was to use the fill command to draw a triangle over the unwanted parts of the plot.  Note that I also make the background color of the plot white, which I ALWAYS do because the default gray is hideous.  Here's some example code:

clear all;  close all;

x = linspace(-10, 10);
y = linspace(0, 20);
M = randn(length(y), length(x));

figure(1)
set(gcf, 'Color', 'w')
imagesc(x, y, M)
axis image
axis xy
set(gca, 'XAxisLocation', 'Top')
ylabel('X [units]', 'FontName', 'Times', 'FontSize', 14)
xlabel('Y [units]', 'FontName', 'Times', 'FontSize', 14)

hold on
xmin = min(xlim);
xmax = max(xlim);
ymin = min(ylim);
ymax = max(ylim);
h = fill([xmin xmax xmax xmin], [ymin ymin ymax ymin], 'w');
set(gca, 'Box', 'off')
set(h, 'EdgeColor', 'w')
plot([xmin xmax], [ymin ymax], 'k-')

This isn't a perfect solution. Changing the color of the background, plot box, etc, will mess it up.  It worked nicely for my application, though.  Here's what the output of the above looks like.

Your mileage will vary depending upon the renderer you use, etc.

Wednesday, March 16, 2011

Git Dashboard - A lightweight local git repository manager and Dashboard widget for OS X

The quick and dirty:  Git Dashboard is a lightweight git repository manager and Dashboard widget that I wrote to organize local repositories.

I use git for a lot of stuff.  I find it useful for document projects (latex mostly) as well as code projects and research projects.  The associated repositories are, to some extent, a snapshot of my work life, and therefore the more organized they are and the more diligent I am about keeping them up to date, the more sane my odd little world is.  But it's hard to keep track of them all.

I have a bad habit of doing a bunch of work and not committing.  Or stopping in the middle of a task --- intending to return to it the next day --- and ending up not coming back to it for days or weeks.  I kept thinking, "Man, it would be nice if I had a simple program that showed a list of my repositories and their statuses to keep track of all of this," but no such program seemed to exist.

So I wrote it myself.

I'm calling it "Git Dashboard".  It's very much a work in progress, but it's already pretty functional.  There's a screen shot of the app itself above and of the Dashboard widget below.  The basic idea is that you tell it where your repositories are (and/or you can have it scan directories recursively to discover repositories) and it keeps an up-to-date list telling you whether or not the repository is clean or dirty, when the last commit was, how many dirty or untracked files there are, etc.  You can double click a repository to launch a git client, and there's toolbar buttons to reveal the folder in Finder or launch Terminal in that directory.

Note that this is not meant to be a git client, like GitX.  Rather, it's a way to organize and keep track of your repositories.  I often use it as a launching point, too.  If I'm working on code for one project and want to commit, I double click on that repository in Git Dashboard to launch GitX so that I can organize my changes, etc.

If you want to check it out, go to my little working Git Dashboard web page and download the most recent dmg.   Note that it presently works only on OS X 10.6 (Snow Leopard), but I might be able to get it to work on 10.5 if there is some demand.  Please do tell me if you find it useful, if you find a bug, or have some ideas to make it better!


 

Friday, August 6, 2010

Managing remote branches with git svn

git svn is a great way to work locally using git for remote svn repositories.  The basic workflow is rebase, hack, commit, hack, commit, etc, rebase, dcommit.  You'll get lots of google results by just searching for git svn.  One feature that's really nice is interactive rebase.  For example, to interactively examine the last 8 (local) commits and have the option to delete or combine commits (squash), do
git rebase -i HEAD~8

I recently needed to create a new feature branch on the remote svn, work on it, and then merge it back into the trunk.  It took a whole lot of digging to figure this out, so I thought I'd share what ended up working. I can't vouch for the optimality or safety of any of this.  I just know that it worked for me.
First of all, I made sure to check out the repository using the --stdlayout option.
git svn clone svn+ssh://user@server/svn/repos/project --stdlayout
Then, to create a new remote svn branch called "new_feature",
git svn branch -m "Branch to add in new_feature." new_feature
And check out the new branch locally
git checkout -b new_feature new_feature
Then the usual.  Hack, commit, etc.  It's not a bad idea to first do "git svn dcommit -n" to make sure your dcommits will go to the branch directory in the remote repository.
When it's finally time to merge back into the trunk (this was the hardest part to find - this post at stackoverflow was really helpful), re-checkout the trunk to a new local branch, which I called "merge".
git checkout remotes/trunk -b merge
This seems to be the key step.  Merge the feature branch with the --squash option.
git merge --squash new_feature
Then commit and dcommit.  You may want to do a dcommit -n to reassure yourself that you're committing to the trunk.
git commit -m "Merge new_feature branch"
git svn dcommit -n  (make sure commit will go to trunk)
git svn dcommit
That's it!  You may want to clean up your branches.  This is what I did.
git checkout remotes/trunk
git checkout -b localtrunk
git branch -D new_feature
git branch -D merge

Tuesday, March 2, 2010

Switch between c/c++ source and header files in Emacs

A pretty common task when editing c/c++ programs is to switch between the source and header files (i.e. file.c or file.cpp and file.h). I had a handy keyboard shortcut in vim to do this and, despite my newfound appreciation for the concept of Emacs, this was one of those things that in practice I was sorely missing. I actually sort of expected it to be built in... M-x switch-from-source-to-header or something, but I didn't find it (please let me know if it exists!). So I did what you're supposed to do with Emacs, I forged my own. It turned out to be a pretty good exercise in learning elisp. I had to figure out how to do if-then-else, a switch statement, some simple logic, how to deal with strings, how to interact with emacs, etc. For example, there's no "else" in elisp, instead you do something like this.
(if (some condition)
    (then action)
  (else action)
)
However, the actions are limited to a single statement. If you want to use more than one, you have to wrap it in a (progn ), like this.
(if (some condition)
    (then action)
  (progn
    (else action 1)
    (else action 2)
    )
)
Anyways, here's my function to switch between source and header files. I'm sure there's a better way to do it. There's a couple shortcomings here - it only knows about ".h", ".c", and ".cpp" extensions and if there is no ".c" or ".cpp" file corresponding to a header, it opens up a ".cpp" file for you (maybe you wanted ".c"...). There ought to be a way around the first problem - you could at least specify a configurable table of extension associations. The second problem may be more of a design decision problem. It works pretty well for me - I develop primarily in c++, so assuming ".cpp" is fine for me. If you want the opposite behavior, just swap ".cpp" and ".c" so they are checked in the opposite order. Of course you could ask for an input, but that goes beyond the scope of what I wanted. Another open question for me is how elisp treats local and global variables. I've purposely chosen short, unintelligible variables names here to avoid clobbering some other global variable. I think the "let" command has something to do with this, but I didn't have time to work it out.
(defun dts-switch-between-header-and-source ()
  "Switch between a c/c++ header (.h) and its corresponding source (.c/.cpp)."
  (interactive)
  ;; grab the base of the current buffer's file name
  (setq bse (file-name-sans-extension buffer-file-name))
  ;; and the extension, converted to lowercase so we can
  ;; compare it to "h", "c", "cpp", etc
  (setq ext (downcase (file-name-extension buffer-file-name)))
  ;; This is like a c/c++ switch statement, except that the
  ;; conditions can be any true/false evaluated statement
  (cond
   ;; first condition - the extension is "h"
   ((equal ext "h")
    ;; first, look for bse.c 
    (setq nfn (concat bse ".c"))
    (if (file-exists-p nfn)
        ;; if it exists, either switch to an already-open
        ;;  buffer containing that file, or open it in a new buffer
        (find-file nfn)
      ;; this is the "else" part - note that if it is more than
      ;;  one line, it needs to be wrapped in a (progn )
      (progn
        ;; look for a bse.cpp
        (setq nfn (concat bse ".cpp"))
        ;; likewise 
        (find-file nfn)
        )
      )
    )
   ;; second condition - the extension is "c" or "cpp"
   ((or (equal ext "cpp") (equal ext "c"))
    ;; look for a corresponding bse.h
    (setq nfn (concat bse ".h"))
    (find-file nfn)
    )
   )
  )
(global-set-key (kbd "C-c s") 'dts-switch-between-header-and-source)

Friday, February 26, 2010

Finally getting gnus to act like an email client

I'm liking emacs. I still miss some of the vim commands, particularly numerical prefixes (I know, in emacs you can do C-u to prefix a command, but it's just not nearly as elegant) and the "repeat last edit" command ".". But on the whole, I like how integrated emacs is, how customizable it is, and actually a few of the editing commands (one of my new favorites is C-x ; to set the comment column then M-; to add a comment at the right of a group of text). Anyways, I've switched to using gnus for my email. It took a little getting used to, but yesterday I tried going back to Mail.app and found myself kind of annoyed at some of the things I just couldn't do; particularly with respect to managing my gmail account, which all of my email goes through. On the other hand, it has taken me over a week to get this to work the way I want it to. The google search results are more often than not not all that helpful, so I thought I'd document some of what I've learned here.

1. Gnus and Gmail imap. I don't remember all of the details of getting it set up, but this part of the .gnus file has the basic set-up for getting your mail from the gmail imap server:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Using gmail IMAP for receiving mail, credentials in .authinfo
(setq gnus-select-method '(nnml ""))
(add-to-list 'gnus-secondary-select-methods '(nnimap "gmail"
                                                     (nnimap-address "imap.gmail.com")
                                                     (nnimap-server-port 993)
                                                     (nnimap-stream ssl)))
;; make gnus NOT ignore [Gmail] mailboxes
(setq gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")
I use my Princeton email address primarily, so to send mail through Princeton smtp I use
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Using Princeton SMTP for sending mail
(setq message-sendmail-envelope-from 'header)
(setq send-mail-function 'smtpmail-send-it
      message-send-mail-function 'smtpmail-send-it)
(setq smtpmail-default-smtp-server "smtp.princeton.edu"
      smtpmail-smtp-server "smtp.princeton.edu"
      smtpmail-smtp-service 587
      smtpmail-starttls-credentials '(("smtp.princeton.edu" 587 nil nil)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This is the "proper" way to set up the "from" information for new mail
;;   Note I BCC to myself @ gmail so that it gets stored in my gmail
(setq gnus-posting-styles
      '((".*"
         (name "Daniel Swain")
         (address "dswain@princeton.edu")
         (BCC "dan.t.swain@gmail.com"))))
For both I use a ~/.authinfo file which should look something like this:
machine imap.gmail.com login dan.t.swain@gmail.com password mysupersecretpassword port 993
machine smtp.princeton.edu login dswain password
myothersupersecretpassword port 587
This bit gets gnus to stop asking me how many old emails I want to download. You could change 'some to some big number, but I keep my inbox pretty clean, so it's not a big deal.
;; don't ask how many emails to download
(setq gnus-large-newsgroup 'nil)
The final bit took me the longest to figure out. Every time I got new email, gnus would only show the new email in the buffer and hide all of my old emails until I read the new one and hit M-g again to rescan the inbox. A bit of C-h k to figure out what the function call was led me to this solution, in which I bind C-c C-c in the summary buffer to "Check for new mail", which is a call to the same function as M-g but with 'all as an argument.
;; tells gnus to get new mail and also display all old mail
(define-key gnus-summary-mode-map (kbd "C-c C-c")
  (lambda ()
    (interactive)
    (gnus-summary-rescan-group 'all)))

2. w3m and Aquamacs 2.0 preview 4b. When I upgraded to Aquamacs 2.0 preview 4b (which is based on Emacs23.1 rather than Emacs22.something), gnus seemed to stop wanting to display the contents of some emails, instead just displaying the headers. It turns out this was because those emails used HTML and w3m uses the w3m browser to show HTML emails. I had download w3m before and installed emacs-w3m under Aquamacs 1.9, but apparently something broke in the upgrade. I was able to fix it by downloading the CVS version of emacs-w3m (I didn't have to reinstall w3m, which I had installed using darwinports) and configuring it using --with-emacs=/Applications/Aquamacs.app/Contents/MacOS/Aquamacs. I did a "make" but not "make install", instead I copied the whole emacs-w3m folder to my emacs packages directory (~/.emacs-pkgs, but the name isn't important) and loading it in my .emacs.el with
;; Use w3m for web browsing
(setq load-path (cons "~/.emacs-pkgs/emacs-w3m/" load-path))
(require 'w3m-load)

3. I used htmlize to generate the code snippets in this post.

Tuesday, February 16, 2010

Posting from Emacs using gblogger

I've been playing with Emacs lately. The MO of Emacs is to avoid leaving it any more than absolutely necessary, so there are packages for doing all kinds of stuff. One of those things is posting to blogger. It didn't take too long to find this article introducing g-client, which can be downloaded from google here. Downloading and installing it were relatively painless, except that you need to run make config before make to avoid errors about missing g-cus-load.el. The hard part was figuring out, for someone who didn't "just know", what the "post url" was. So here's how you figure it out. Run gblogger-blogs and view the resulting page (for me it just opened in my browser) - it should be a plain text page with a handful of links. At the bottom of the page is a link "[post]". Right click and copy the address for that - that's the "post url". Having that, I of course started hacking my .emacs.el:

(defun dts-new-blog-post ()
(interactive)
(gblogger-new-entry "http://www.blogger.com/feeds/7785890353048895648/posts/default"))
and mapped it to C-c C-b.

BTW 1 - It was super easy to copy and paste the code from my .emacs.el, since it was open in another buffer.

BTW 2 - In writing this I found the following two commands really useful:

w3m-print-current-url
Prints the url of the current page in the minibuffer, but, possibly more useful, copies it to the kill-ring.
w3m-print-this-url
Same as above, but for the currently hilighted link.

BTW 3 - When trying to post this it complained that I had an HTML error and I freaked a little about getting my post back, but all I had to do was undo a couple times (C-x u).

BTW 4 - I went back and edited this post to remove some extra blank lines. Unlike normal HTML, they seem to matter here and were producing MEGA spacing.