color tab support

This commit is contained in:
John Bintz 2011-07-02 16:57:31 -04:00
parent f206847274
commit 81a8462103
4 changed files with 210 additions and 27 deletions

View File

@ -11,4 +11,6 @@ Gem::Specification.new do |s|
s.has_rdoc = true s.has_rdoc = true
s.add_development_dependency 'rspec', '~> 2.6.0' s.add_development_dependency 'rspec', '~> 2.6.0'
s.add_development_dependency 'fakefs'
s.add_development_dependency 'mocha'
end end

View File

@ -67,15 +67,18 @@
# first_tab.select # brings first tab back to focus # first_tab.select # brings first tab back to focus
# end # end
require 'tempfile'
# The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands. # The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands.
class ItermWindow class ItermWindow
attr_reader :tab_color_files
# While you can directly use ItermWindow.new, using either ItermWindow.open or # While you can directly use ItermWindow.new, using either ItermWindow.open or
# ItermWindow.current is the preferred method. # ItermWindow.current is the preferred method.
def initialize def initialize
@buffer = [] @buffer = []
@tabs = {} @tabs = {}
@tab_color_files = []
end end
# Creates a new terminal window, runs the block on it # Creates a new terminal window, runs the block on it
@ -105,16 +108,18 @@ class ItermWindow
# Outputs a single line of Applescript code # Outputs a single line of Applescript code
def output(command) def output(command)
@buffer << command.gsub(/'/, '"') @buffer << command.gsub("'", '"').gsub('\\', '\\\\\\')
end end
def concatenated_buffer
@buffer.join("\n")
end
private private
# Outputs @buffer to the command line as an osascript function # Outputs @buffer to the command line as an osascript function
def send_output def send_output
buffer_str = @buffer.map {|line| "-e '#{line}'"}.join(' ') shell_out
shell_out "osascript #{buffer_str}"
end end
# Initializes the terminal window # Initializes the terminal window
@ -137,16 +142,18 @@ class ItermWindow
create_tab_convenience_method(name) create_tab_convenience_method(name)
end end
private
def create_tab_convenience_method(name) def create_tab_convenience_method(name)
(class << self; self; end).send(:define_method, name) do (class << self; self; end).send(:define_method, name) do
@tabs[name] @tabs[name]
end end
end end
def shell_out(str) def shell_out
%x{str} Tempfile.open('iterm') do |f|
f.print concatenated_buffer
f.close
system %{osascript #{f.path}}
end
end end
@ -194,6 +201,15 @@ class ItermWindow
end end
end end
# Sets the title of the tab (ie the text on the iTerm tab itself)
def tab_color(color)
if @currently_executing_block
output "write text 'cat #{file = create_tab_color_file(color)} && rm #{file}'"
else
execute_block { tab_color(color) }
end
end
# Runs a block on this tab with proper opening and closing statements # Runs a block on this tab with proper opening and closing statements
def execute_block(&block) def execute_block(&block)
@currently_executing_block = true @currently_executing_block = true
@ -203,13 +219,34 @@ class ItermWindow
@currently_executing_block = false @currently_executing_block = false
end end
def self.create_tab_color(color)
raise ArgumentError.new("bad hex color: #{color}") if color.downcase[%r{[^a-f0-9]}] || !([ 3, 6 ].include?(color.length))
%w{red green blue}.zip(color.scan(
(case color.length
when 3
/./
when 6
/../
end)
).collect { |part|
part += part if part.length == 1
part.hex
}).collect do |color, brightness|
"\033]6;1;bg;#{color};brightness;#{brightness}\a"
end.join
end
private private
def output(command) def output(command)
@window.output command @window.output command
end end
def create_tab_color_file(color)
file = Tempfile.open('iterm').path + '.tc'
File.open(file, 'wb') { |f| f.puts self.class.create_tab_color(color) }
@window.tab_color_files << file
file
end
end end
end
end

View File

@ -4,12 +4,13 @@ require 'iterm_window'
describe ItermWindow do describe ItermWindow do
before(:each) do before(:each) do
@window = ItermWindow.new @window = ItermWindow.new
Kernel.stubs(:system)
end end
describe ".current" do describe ".current" do
it "should instantiate the current window and run the block" do it "should instantiate the current window and run the block" do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
@window.should_receive(:run).with(:current) @window.expects(:run).with(:current)
ItermWindow.current do ItermWindow.current do
end end
@ -18,8 +19,8 @@ describe ItermWindow do
describe ".open" do describe ".open" do
it "should instantiate a new window and run the block" do it "should instantiate a new window and run the block" do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
@window.should_receive(:run).with(:new) @window.expects(:run).with(:new)
ItermWindow.open do ItermWindow.open do
end end
@ -28,12 +29,25 @@ describe ItermWindow do
describe "opening a tab (example 1)" do describe "opening a tab (example 1)" do
before(:each) do before(:each) do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
end end
it "should generate and run the right Applescript" do it "should generate and run the right Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to (make new terminal)' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set my_tab_tty to the tty of the last session' -e 'tell session id my_tab_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'end tell' -e 'end tell' -e 'end tell'" desired = (<<-CMD).strip
@window.should_receive(:shell_out).with(desired) tell application "iTerm"
activate
set myterm to (make new terminal)
tell myterm
launch session "Default Session"
set my_tab_tty to the tty of the last session
tell session id my_tab_tty
write text \"cd ~/projects/my_project/trunk\"
write text \"mate ./\"
end tell
end tell
end tell
CMD
@window.expects(:shell_out)
ItermWindow.open do ItermWindow.open do
open_tab :my_tab do open_tab :my_tab do
@ -41,17 +55,47 @@ describe ItermWindow do
write "mate ./" write "mate ./"
end end
end end
@window.concatenated_buffer.should == desired
end end
end end
describe "open multiple tabs (example 2)" do describe "open multiple tabs (example 2)" do
before(:each) do before(:each) do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
end end
it "should generate and run the right Applescript" do it "should generate and run the right Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to first terminal' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set project_dir_tty to the tty of the last session' -e 'tell session id project_dir_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'set name to \"MyProject Dir\"' -e 'end tell' -e 'launch session \"Default Session\"' -e 'set server_tty to the tty of the last session' -e 'tell session id server_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"script/server -p 3005\"' -e 'set name to \"MyProject Server\"' -e 'end tell' -e 'launch session \"Default Session\"' -e 'set console_tty to the tty of the last session' -e 'tell session id console_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"script/console\"' -e 'set name to \"MyProject Console\"' -e 'end tell' -e 'end tell' -e 'end tell'" desired = (<<-CMD).strip
@window.should_receive(:shell_out).with(desired) tell application "iTerm"
activate
set myterm to first terminal
tell myterm
launch session "Default Session"
set project_dir_tty to the tty of the last session
tell session id project_dir_tty
write text "cd ~/projects/my_project/trunk"
write text "mate ./"
set name to "MyProject Dir"
end tell
launch session "Default Session"
set server_tty to the tty of the last session
tell session id server_tty
write text "cd ~/projects/my_project/trunk"
write text "script/server -p 3005"
set name to "MyProject Server"
end tell
launch session "Default Session"
set console_tty to the tty of the last session
tell session id console_tty
write text "cd ~/projects/my_project/trunk"
write text "script/console"
set name to "MyProject Console"
end tell
end tell
end tell
CMD
@window.expects(:shell_out)
ItermWindow.current do ItermWindow.current do
open_tab :project_dir do open_tab :project_dir do
@ -72,17 +116,37 @@ describe ItermWindow do
set_title "MyProject Console" set_title "MyProject Console"
end end
end end
@window.concatenated_buffer.should == desired
end end
end end
describe "open tabs using bookmarks (example 3)" do describe "open tabs using bookmarks (example 3)" do
before(:each) do before(:each) do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
end end
it "should generate and run the correct Applescript" do it "should generate and run the correct Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to first terminal' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set project_dir_tty to the tty of the last session' -e 'tell session id project_dir_tty' -e 'write text \"cd ~/projects/my_project/trunk\"' -e 'write text \"mate ./\"' -e 'end tell' -e 'launch session \"MyProject Server\"' -e 'set server_tty to the tty of the last session' -e 'launch session \"MyProject Console\"' -e 'set console_tty to the tty of the last session' -e 'select session id project_dir_tty' -e 'end tell' -e 'end tell'" desired = (<<-CMD).strip
@window.should_receive(:shell_out).with(desired) tell application "iTerm"
activate
set myterm to first terminal
tell myterm
launch session "Default Session"
set project_dir_tty to the tty of the last session
tell session id project_dir_tty
write text "cd ~/projects/my_project/trunk"
write text "mate ./"
end tell
launch session "MyProject Server"
set server_tty to the tty of the last session
launch session "MyProject Console"
set console_tty to the tty of the last session
select session id project_dir_tty
end tell
end tell
CMD
@window.stubs(:shell_out)
ItermWindow.current do ItermWindow.current do
open_tab :project_dir do open_tab :project_dir do
@ -95,17 +159,38 @@ describe ItermWindow do
project_dir.select project_dir.select
end end
@window.concatenated_buffer.should == desired
end end
end end
describe "switching between tabs (example 4)" do describe "switching between tabs (example 4)" do
before(:each) do before(:each) do
ItermWindow.should_receive(:new).and_return(@window) ItermWindow.expects(:new).returns(@window)
end end
it "should generate and run the correct Applescript" do it "should generate and run the correct Applescript" do
desired = "osascript -e 'tell application \"iTerm\"' -e 'activate' -e 'set myterm to (make new terminal)' -e 'tell myterm' -e 'launch session \"Default Session\"' -e 'set first_tab_tty to the tty of the last session' -e 'launch session \"Default Session\"' -e 'set second_tab_tty to the tty of the last session' -e 'tell session id first_tab_tty' -e 'write text \"cd ~/projects\"' -e 'write text \"ls\"' -e 'end tell' -e 'tell session id second_tab_tty' -e 'write text \"echo \"hello there!\"\"' -e 'end tell' -e 'select session id first_tab_tty' -e 'end tell' -e 'end tell'" desired = (<<-CMD).strip
@window.should_receive(:shell_out).with(desired) tell application "iTerm"
activate
set myterm to (make new terminal)
tell myterm
launch session "Default Session"
set first_tab_tty to the tty of the last session
launch session "Default Session"
set second_tab_tty to the tty of the last session
tell session id first_tab_tty
write text "cd ~/projects"
write text "ls"
end tell
tell session id second_tab_tty
write text "echo "hello there!""
end tell
select session id first_tab_tty
end tell
end tell
CMD
@window.expects(:shell_out)
ItermWindow.open do ItermWindow.open do
open_tab :first_tab open_tab :first_tab
@ -117,6 +202,61 @@ describe ItermWindow do
second_tab.write "echo 'hello there!'" second_tab.write "echo 'hello there!'"
first_tab.select first_tab.select
end end
@window.concatenated_buffer.should == desired
end
end
describe 'tab color' do
before(:each) do
ItermWindow.expects(:new).returns(@window)
end
it "should generate and run the correct Applescript" do
@window.expects(:shell_out)
ItermWindow::Tab.any_instance.expects(:create_tab_color_file).with("FF00AA")
ItermWindow.open do
open_tab :first_tab do
tab_color "FF00AA"
end
end
end
end
describe ".create_tab_color" do
subject { ItermWindow::Tab.create_tab_color(color) }
context 'bad hex color' do
[ "whatever", "F00F" ].each do |bad|
context bad do
let(:color) { bad }
it 'should raise an exception on bad hex color' do
expect { subject }.to raise_error(ArgumentError, /bad hex color/)
end
end
end
end
context 'long hex color' do
let(:color) { "FF00AA" }
it 'should create an escape sequence to execute to change a tab color' do
subject.should match(/red;brightness;255/)
subject.should match(/green;brightness;0/)
subject.should match(/blue;brightness;170/)
end
end
context 'short hex color' do
let(:color) { "F0A" }
it 'should create an escape sequence to execute to change a tab color' do
subject.should match(/red;brightness;255/)
subject.should match(/green;brightness;0/)
subject.should match(/blue;brightness;170/)
end
end end
end end
end end

View File

@ -0,0 +1,4 @@
RSpec.configure do |c|
c.mock_with :mocha
end