Skip to content

Instantly share code, notes, and snippets.

@oggy
Created March 6, 2014 18:08
Show Gist options
  • Save oggy/9395830 to your computer and use it in GitHub Desktop.
Save oggy/9395830 to your computer and use it in GitHub Desktop.
Command line program for Aquamacs
#!/usr/bin/env ruby
######################################################################
#
# Open the given file names in Aquamacs.
#
# If the user already has an Aquamacs process open, use it.
# Otherwise, fire up a new one. Only Aquamacs instances without a
# controlling terminal (i.e., those running in a window) will be
# selected.
#
# Note: We assume the server socket lives in the standard location:
# /tmp/emacs<uid>/server.
#
######################################################################
require 'optparse'
require 'tmpdir'
class App
def initialize
@emacs = find_emacs
@socket = find_socket
@verbose = false
end
attr_reader :emacs, :socket, :verbose
def run(args)
parse_args(args)
emacs or
abort "Cannot find emacs. Set EMACS, or use -e option."
puts "Using emacs: #{emacs}" if verbose
if aquamacs_running?
exec emacs_path('bin/emacsclient'), '--no-wait', "--socket-name=#{socket}", *args
else
puts 'Starting Aquamacs...'
# We can't just use the open command, as it will always open
# Aquamacs as the logged-in user, and we want to run as the user who
# ran this program (e.g., for sudo).
# Fork so it runs in the background.
fork do
# Lose the controlling terminal.
Process.setsid
# Silence errors. If we run this as someone other than the
# logged-in user, Aquamacs gets a permissions error trying to
# register itself as a service and cries loudly.
STDERR.reopen('/dev/null') unless verbose
exec emacs_path('Aquamacs', 'Aquamacs Emacs'), *args
end
end
end
def parse_args(args)
parser = OptionParser.new do |parser|
parser.on('-e', '--emacs=PATH', "Path to Aquamacs. Default: #{emacs}") { |path| @emacs = path }
parser.on('-s', '--socket=PATH', "Path to server socket. Default: #{socket}") { |path| @socket = path }
parser.on('-v', '--verbose', "Show all errors.") { |path| @verbose = true }
end
parser.parse!(args)
args.size >= 1 or
abort 'No files given.'
end
def find_emacs
emacs = ENV['EMACS'] and
return emacs
['Aquamacs.app', 'Aquamacs Emacs.app'].each do |app_name|
['~/Applications', '/Applications'].each do |app_path|
path = File.expand_path("#{app_path}/#{app_name}")
return path if File.exist?(path)
end
end
nil
end
def find_socket
tmp_dir = Dir.tmpdir
"#{tmp_dir}/emacs#{Process.uid}/server"
end
def emacs_path(*names)
names.each do |name|
path = "#{emacs}/Contents/MacOS/#{name}"
return path if File.exist?(path)
end
nil
end
def aquamacs_running?
`ps -U #{ENV['USER']} -xwwo tpgid,command`.each_line do |line|
tpgid, command = *line.split(nil, 2)
# Assume Aquamacs instances with a controlling terminal are
# running inside a terminal window. Any instances we launch will
# have no controlling terminal.
return true if command =~ /\A#{Regexp.escape emacs}/ && tpgid == '0'
end
false
end
end
App.new.run(ARGV)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment