From 6220be10de6158b8f780087150b0403ddaefa7be Mon Sep 17 00:00:00 2001 From: John Bintz Date: Sun, 17 Jul 2011 09:34:02 -0400 Subject: [PATCH] start work on multi-terminal support --- lib/iterm/interface/iterm.rb | 88 +++++++ lib/iterm/interface/konsole.rb | 0 lib/iterm/tab.rb | 82 ++++++ lib/iterm/window.rb | 123 +++++++++ lib/iterm_window.rb | 229 ----------------- spec/iterm/interface/iterm_spec.rb | 106 ++++++++ spec/iterm/tab_spec.rb | 32 +++ spec/iterm/window_spec.rb | 313 +++++++++++++++++++++++ spec/iterm_window_spec.rb | 386 ----------------------------- 9 files changed, 744 insertions(+), 615 deletions(-) create mode 100644 lib/iterm/interface/iterm.rb create mode 100644 lib/iterm/interface/konsole.rb create mode 100644 lib/iterm/tab.rb create mode 100644 lib/iterm/window.rb create mode 100644 spec/iterm/interface/iterm_spec.rb create mode 100644 spec/iterm/tab_spec.rb create mode 100644 spec/iterm/window_spec.rb diff --git a/lib/iterm/interface/iterm.rb b/lib/iterm/interface/iterm.rb new file mode 100644 index 0000000..6033c34 --- /dev/null +++ b/lib/iterm/interface/iterm.rb @@ -0,0 +1,88 @@ +module Iterm + module Interface + class Iterm + attr_reader :buffer, :window + + class << self + def 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 + end + + def initialize(window) + @window = window + @buffer = [] + end + + def <<(command) + @buffer << command.gsub("'", '"').gsub('\\', '\\\\\\') + end + + def execute(window_type, &block) + window_types = {:new => '(make new terminal)', :current => 'first terminal'} + raise ArgumentError, "Iterm::Window#run_commands should be passed :new or :current." unless window_types.keys.include? window_type + self << "tell application 'iTerm'" + self << "activate" + self << "set myterm to #{window_types[window_type]}" + self << "tell myterm" + + window.instance_eval(&block) if block_given? + + self << "end tell" + self << "end tell" + end + + def concatenated_buffer + @buffer.join("\n") + end + + def new_session(name, bookmark = nil) + self << "launch session '#{bookmark}'" + self << "set #{name}_tty to the tty of the last session" + end + + def cd(dir) + self << write("cd #{dir}") + end + + def chrome_color(color) + self << write("cat #{file = create_tab_color_file(color)} && rm #{file}") + end + + private + def write(text) + %{write text "#{text}"} + 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(ensure_color(color)) } + @window.tab_color_files << file + file + end + + def ensure_color(color) + case color + when Symbol + Iterm::Window.colors[color] + else + color + end + end + end + end +end + diff --git a/lib/iterm/interface/konsole.rb b/lib/iterm/interface/konsole.rb new file mode 100644 index 0000000..e69de29 diff --git a/lib/iterm/tab.rb b/lib/iterm/tab.rb new file mode 100644 index 0000000..1ba6d6c --- /dev/null +++ b/lib/iterm/tab.rb @@ -0,0 +1,82 @@ +require 'iterm/window' +require 'forwardable' + +module Iterm +# The Tab class models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby. +class Tab + extend Forwardable + attr_reader :name, :bookmark, :window + + def_delegators :window, :interface + + def initialize(window, name, bookmark = nil, options = {}, &block) + @name, @bookmark, @window = name, bookmark, window + + @currently_executing_block = false + + interface.new_session(@name, @bookmark) + interface.cd(options[:dir]) if options[:dir] + interface.chrome_color(options[:color]) if options[:color] + + execute_block &block if block_given? + end + + # Brings a tab into focus, runs a block on it if passed + def select(&block) + if block_given? + execute_block &block + else + output "select session id #{name}_tty" + end + end + + # Writes a command into the terminal tab + def write(command) + if @currently_executing_block + output "write text '#{command}'" + else + execute_block { write command } + end + end + + # Sets the title of the tab (ie the text on the iTerm tab itself) + def set_title(str) + if @currently_executing_block + output "set name to '#{str}'" + else + execute_block { set_title = str } + end + end + + # Sets the title of the tab (ie the text on the iTerm tab itself) + def tab_color(color) + if @currently_executing_block + interface.chrome_color(color) + else + execute_block { tab_color(color) } + end + end + + # Runs a block on this tab with proper opening and closing statements + def execute_block(&block) + @currently_executing_block = true + output "tell session id #{name}_tty" + self.instance_eval(&block) + output "end tell" + @currently_executing_block = false + end + + def method_missing(name, *args) + write("#{name} #{args.join(' ')}") + end + + +private + +def output(command) + @window.output command +end + +end +end + diff --git a/lib/iterm/window.rb b/lib/iterm/window.rb new file mode 100644 index 0000000..a6e98a4 --- /dev/null +++ b/lib/iterm/window.rb @@ -0,0 +1,123 @@ +require 'tempfile' +require 'iterm/tab' +require 'iterm/interface/iterm' +require 'forwardable' + +module Iterm + class Window + extend Forwardable + + attr_reader :tab_color_files, :interface + + def_delegators :interface, :concatenated_buffer + + class << self + def colors=(colors) + @colors = colors + end + + def colors + @colors + end + + def add_command(name, &block) + Iterm::Tab.send(:define_method, name, block) + end + + def run_file(file) + instance_eval(file) + end + + # Creates a new terminal window, runs the block on it + def open(options = {}, &block) + new.run(:new, options, &block) + end + + # Selects the first terminal window, runs the block on it + def current(&block) + new.run(:current, &block) + end + end + + Window.colors = { + :rails => 'F99', + :rspec => '99F', + :js => '9F9', + :doc => 'FF9', + :log => 'DFF', + } + + # While you can directly use ItermWindow.new, using either ItermWindow.open or + # ItermWindow.current is the preferred method. + def initialize + @buffer = [] + @tabs = {} + @tab_color_files = [] + @default_tab = nil + + @interface = Iterm::Interface::Iterm.new(self) + end + + def run(window_type = :new, options = {}, &block) + @options = options + run_commands window_type, &block + send_output + end + + # Creates a new tab from a bookmark, runs the block on it + def open_bookmark(name, bookmark, &block) + create_tab(name, bookmark, &block) + end + + # Creates a new tab from 'Default Session', runs the block on it + def open_tab(name, options = {}, &block) + create_tab(name, 'Default Session', options, &block) + + @default_tab = name if options[:default] + end + + def default_tab(name, options = {}, &block) + open_tab(name, options.merge(:default => true), &block) + end + + def output(line) + @interface << line + end + + private + + # Outputs @buffer to the command line as an osascript function + def send_output + shell_out + end + + # Initializes the terminal window + def run_commands(window_type, &block) + @interface.execute(window_type) do + instance_eval(&block) + @tabs[@default_tab].select if @default_tab + end + end + + # Creates a new Tab object, either default or from a bookmark, + # and creates a convenience method for retrieval + def create_tab(name, bookmark=nil, options = {}, &block) + @tabs[name] = Tab.new(self, name, bookmark, @options.merge(options), &block) + create_tab_convenience_method(name) + end + + def create_tab_convenience_method(name) + (class << self; self; end).send(:define_method, name) do + @tabs[name] + end + end + + def shell_out + Tempfile.open('iterm') do |f| + f.print concatenated_buffer + f.close + system %{osascript #{f.path}} + end + end + end +end diff --git a/lib/iterm_window.rb b/lib/iterm_window.rb index 81b9031..ccb60cf 100755 --- a/lib/iterm_window.rb +++ b/lib/iterm_window.rb @@ -67,236 +67,7 @@ # first_tab.select # brings first tab back to focus # end -require 'tempfile' # The ItermWindow class models an iTerm terminal window and allows for full control via Ruby commands. -class ItermWindow - attr_reader :tab_color_files - - class << self - def colors=(colors) - @colors = colors - end - - def colors - @colors - end - - def add_command(name, &block) - ItermWindow::Tab.send(:define_method, name, block) - end - end - - ItermWindow.colors = { - :rails => 'F99', - :rspec => '99F', - :js => '9F9', - :doc => 'FF9', - :log => 'DFF', - } - - # While you can directly use ItermWindow.new, using either ItermWindow.open or - # ItermWindow.current is the preferred method. - def initialize - @buffer = [] - @tabs = {} - @tab_color_files = [] - @default_tab = nil - end - - def self.run_file(file) - instance_eval(file) - end - - # Creates a new terminal window, runs the block on it - def self.open(options = {}, &block) - self.new.run(:new, options, &block) - end - - # Selects the first terminal window, runs the block on it - def self.current(&block) - self.new.run(:current, &block) - end - - def run(window_type = :new, options = {}, &block) - @options = options - run_commands window_type, &block - send_output - end - - # Creates a new tab from a bookmark, runs the block on it - def open_bookmark(name, bookmark, &block) - create_tab(name, bookmark, &block) - end - - # Creates a new tab from 'Default Session', runs the block on it - def open_tab(name, options = {}, &block) - create_tab(name, 'Default Session', options, &block) - @default_tab = name if options[:default] - end - - def default_tab(name, options = {}, &block) - open_tab(name, options.merge(:default => true), &block) - end - - # Outputs a single line of Applescript code - def output(command) - @buffer << command.gsub("'", '"').gsub('\\', '\\\\\\') - end - - def concatenated_buffer - @buffer.join("\n") - end - - private - - # Outputs @buffer to the command line as an osascript function - def send_output - shell_out - end - - # Initializes the terminal window - def run_commands(window_type, &block) - window_types = {:new => '(make new terminal)', :current => 'first terminal'} - raise ArgumentError, "ItermWindow#run_commands should be passed :new or :current." unless window_types.keys.include? window_type - output "tell application 'iTerm'" - output "activate" - output "set myterm to #{window_types[window_type]}" - output "tell myterm" - self.instance_eval(&block) if block_given? - @tabs[@default_tab].select if @default_tab - output "end tell" - output "end tell" - end - - # Creates a new Tab object, either default or from a bookmark, - # and creates a convenience method for retrieval - def create_tab(name, bookmark=nil, options = {}, &block) - @tabs[name] = Tab.new(self, name, bookmark, @options.merge(options), &block) - create_tab_convenience_method(name) - end - - def create_tab_convenience_method(name) - (class << self; self; end).send(:define_method, name) do - @tabs[name] - end - end - - def shell_out - Tempfile.open('iterm') do |f| - f.print concatenated_buffer - f.close - system %{osascript #{f.path}} - end - end - # The Tab class models a tab (session) in an iTerm terminal window and allows for it to be controlled by Ruby. - class Tab - - attr_reader :name - attr_reader :bookmark - - def initialize(window, name, bookmark = nil, options = {}, &block) - @name = name - @bookmark = bookmark - @window = window - @currently_executing_block = false - output "launch session '#{@bookmark}'" - # store tty id for later access - output "set #{name}_tty to the tty of the last session" - write "cd #{options[:dir]}" if options[:dir] - tab_color options[:color] if options[:color] - - execute_block &block if block_given? - end - - # Brings a tab into focus, runs a block on it if passed - def select(&block) - if block_given? - execute_block &block - else - output "select session id #{name}_tty" - end - end - - # Writes a command into the terminal tab - def write(command) - if @currently_executing_block - output "write text '#{command}'" - else - execute_block { write command } - end - end - - # Sets the title of the tab (ie the text on the iTerm tab itself) - def set_title(str) - if @currently_executing_block - output "set name to '#{str}'" - else - execute_block { set_title = str } - 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 - def execute_block(&block) - @currently_executing_block = true - output "tell session id #{name}_tty" - self.instance_eval(&block) - output "end tell" - @currently_executing_block = false - end - - def method_missing(name, *args) - write("#{name} #{args.join(' ')}") - 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 - - def output(command) - @window.output command - 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(ensure_color(color)) } - @window.tab_color_files << file - file - end - - def ensure_color(color) - case color - when Symbol - ItermWindow.colors[color] - else - color - end - end - end -end diff --git a/spec/iterm/interface/iterm_spec.rb b/spec/iterm/interface/iterm_spec.rb new file mode 100644 index 0000000..eeeb8ef --- /dev/null +++ b/spec/iterm/interface/iterm_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' +require 'iterm/interface/iterm' + +describe Iterm::Interface::Iterm do + let(:iterm) { described_class.new(self) } + + describe "#execute" do + it 'should create a new terminal' do + iterm.execute(:new) do + end + + iterm.concatenated_buffer.should == (<<-TXT).strip +tell application "iTerm" +activate +set myterm to (make new terminal) +tell myterm +end tell +end tell + TXT + end + + it 'should use the current terminal' do + iterm.execute(:current) do + end + + iterm.concatenated_buffer.should == (<<-TXT).strip +tell application "iTerm" +activate +set myterm to first terminal +tell myterm +end tell +end tell + TXT + end + end + + describe '#<<' do + it 'should add a line of output to the buffer' do + iterm << "my 'command'" + iterm.buffer.should == [ %{my "command"} ] + end + end + + describe '#new_session' do + it 'should start a new session' do + iterm.new_session('one', 'two') + + iterm.concatenated_buffer.should =~ /one/ + iterm.concatenated_buffer.should =~ /two/ + end + end + + describe '#cd' do + it 'should write the command to cd to a directory' do + iterm.cd('/here/there') + + iterm.concatenated_buffer.should == %{write text "cd /here/there"} + end + end + + describe '#chrome_color' do + it "should generate and run the correct Applescript" do + iterm.expects(:create_tab_color_file).with("FF00AA") + iterm.chrome_color("FF00AA") + + iterm.concatenated_buffer.should =~ /cat / + end + end + + describe ".create_tab_color" do + subject { described_class.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 + diff --git a/spec/iterm/tab_spec.rb b/spec/iterm/tab_spec.rb new file mode 100644 index 0000000..81f30b9 --- /dev/null +++ b/spec/iterm/tab_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'iterm/tab' +require 'iterm/window' + +describe Iterm::Tab do + before(:each) do + @window = Iterm::Window.new + Kernel.stubs(:system) + end + + describe '#tab_color' do + it 'should generate color in a tab definition' do + @window.expects(:shell_out) + @window.interface.expects(:chrome_color).with("FF00AA") + + @window.run do + open_tab :first_tab, :color => "FF00AA" do + end + end + end + + it 'should use predetermined colors' do + @window.expects(:shell_out) + @window.interface.expects(:chrome_color).with(:rails) + + @window.run do + open_tab :first_tab, :color => :rails do + end + end + end + end +end diff --git a/spec/iterm/window_spec.rb b/spec/iterm/window_spec.rb new file mode 100644 index 0000000..1f8169b --- /dev/null +++ b/spec/iterm/window_spec.rb @@ -0,0 +1,313 @@ +require 'spec_helper' +require 'iterm/window' + +describe Iterm::Window do + before(:each) do + @window = Iterm::Window.new + Kernel.stubs(:system) + end + + describe ".current" do + it "should instantiate the current window and run the block" do + Iterm::Window.expects(:new).returns(@window) + @window.expects(:run).with(:current) + Iterm::Window.current do + + end + end + end + + describe ".open" do + it "should instantiate a new window and run the block" do + Iterm::Window.expects(:new).returns(@window) + @window.expects(:run).with(:new, {}) + Iterm::Window.open do + + end + end + end + + describe '.run_file' do + it "should read the file and create a window" do + Iterm::Window.expects(:new).returns(@window) + @window.expects(:run).with(:new, {}) + Iterm::Window.run_file(<<-FILE) +open do + open_tab :test +end +FILE + end + end + + describe '.add_command' do + before do + Iterm::Tab.send(:remove_method, :test) rescue nil + end + + it 'should define a method on the Tab class' do + Iterm::Window.add_command :test do |params| + params + end + + Iterm::Tab.should have_a_method_named(:test, 1) + end + + after do + Iterm::Tab.send(:remove_method, :test) rescue nil + end + end + + describe "opening a tab (example 1)" do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should generate and run the right Applescript" do + desired = (<<-CMD).strip +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) + + Iterm::Window.open do + open_tab :my_tab do + write "cd ~/projects/my_project/trunk" + write "mate ./" + end + end + + @window.concatenated_buffer.should == desired + end + end + + describe "open multiple tabs (example 2)" do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should generate and run the right Applescript" do + desired = (<<-CMD).strip +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) + + Iterm::Window.current do + open_tab :project_dir do + write "cd ~/projects/my_project/trunk" + write "mate ./" + set_title "MyProject Dir" + end + + open_tab :server do + write "cd ~/projects/my_project/trunk" + write "script/server -p 3005" + set_title "MyProject Server" + end + + open_tab :console do + write "cd ~/projects/my_project/trunk" + write "script/console" + set_title "MyProject Console" + end + end + + @window.concatenated_buffer.should == desired + end + end + + describe "open tabs using bookmarks (example 3)" do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should generate and run the correct Applescript" do + desired = (<<-CMD).strip +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) + + Iterm::Window.current do + open_tab :project_dir do + write "cd ~/projects/my_project/trunk" + write "mate ./" + end + + open_bookmark :server, 'MyProject Server' + open_bookmark :console, 'MyProject Console' + + project_dir.select + end + + @window.concatenated_buffer.should == desired + end + end + + describe "switching between tabs (example 4)" do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should generate and run the correct Applescript" do + desired = (<<-CMD).strip +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) + + Iterm::Window.open do + open_tab :first_tab + open_tab :second_tab + first_tab.select do + write 'cd ~/projects' + write 'ls' + end + second_tab.write "echo 'hello there!'" + first_tab.select + end + + @window.concatenated_buffer.should == desired + end + end + + describe 'magic commands' do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should cd to the directory for the tab" do + @window.expects(:shell_out) + + Iterm::Window.open do + open_tab :first_tab do + bundle "exec guard" + end + end + + @window.concatenated_buffer.should match(/write text "bundle exec guard"/) + end + end + + describe 'default tab' do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should mark the tab as the default tab" do + @window.expects(:shell_out) + + Iterm::Window.open do + open_tab :first_tab, :default => true do + end + end + + @window.concatenated_buffer.should match(/select session id first_tab_tty/) + end + + it "should mark the tab as the default tab" do + @window.expects(:shell_out) + + Iterm::Window.open do + default_tab :first_tab do + end + end + + @window.concatenated_buffer.should match(/select session id first_tab_tty/) + end + end + + describe 'change directory' do + before(:each) do + Iterm::Window.expects(:new).returns(@window) + end + + it "should cd to the directory for the tab" do + @window.expects(:shell_out) + + Iterm::Window.open do + open_tab :first_tab, :dir => 'my-dir' do + end + end + + @window.concatenated_buffer.should match(/cd my-dir/) + end + + it "should cd to the directry for all tabs" do + @window.expects(:shell_out) + + Iterm::Window.open :dir => 'my-dir' do + open_tab :first_tab do + end + end + + @window.concatenated_buffer.should match(/cd my-dir/) + end + end +end diff --git a/spec/iterm_window_spec.rb b/spec/iterm_window_spec.rb index a05b326..e69de29 100644 --- a/spec/iterm_window_spec.rb +++ b/spec/iterm_window_spec.rb @@ -1,386 +0,0 @@ -require 'spec_helper' -require 'iterm_window' - -describe ItermWindow do - before(:each) do - @window = ItermWindow.new - Kernel.stubs(:system) - end - - describe ".current" do - it "should instantiate the current window and run the block" do - ItermWindow.expects(:new).returns(@window) - @window.expects(:run).with(:current) - ItermWindow.current do - - end - end - end - - describe ".open" do - it "should instantiate a new window and run the block" do - ItermWindow.expects(:new).returns(@window) - @window.expects(:run).with(:new, {}) - ItermWindow.open do - - end - end - end - - describe '.run_file' do - it "should read the file and create a window" do - ItermWindow.expects(:new).returns(@window) - @window.expects(:run).with(:new, {}) - ItermWindow.run_file(<<-FILE) -open do - open_tab :test -end -FILE - end - end - - describe '.add_command' do - before do - ItermWindow::Tab.send(:remove_method, :test) rescue nil - end - - it 'should define a method on the Tab class' do - ItermWindow.add_command :test do |params| - params - end - - ItermWindow::Tab.should have_a_method_named(:test, 1) - end - - after do - ItermWindow::Tab.send(:remove_method, :test) rescue nil - end - end - - describe "opening a tab (example 1)" do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should generate and run the right Applescript" do - desired = (<<-CMD).strip -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 - open_tab :my_tab do - write "cd ~/projects/my_project/trunk" - write "mate ./" - end - end - - @window.concatenated_buffer.should == desired - end - end - - describe "open multiple tabs (example 2)" do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should generate and run the right Applescript" do - desired = (<<-CMD).strip -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 - open_tab :project_dir do - write "cd ~/projects/my_project/trunk" - write "mate ./" - set_title "MyProject Dir" - end - - open_tab :server do - write "cd ~/projects/my_project/trunk" - write "script/server -p 3005" - set_title "MyProject Server" - end - - open_tab :console do - write "cd ~/projects/my_project/trunk" - write "script/console" - set_title "MyProject Console" - end - end - - @window.concatenated_buffer.should == desired - end - end - - describe "open tabs using bookmarks (example 3)" do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should generate and run the correct Applescript" do - desired = (<<-CMD).strip -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 - open_tab :project_dir do - write "cd ~/projects/my_project/trunk" - write "mate ./" - end - - open_bookmark :server, 'MyProject Server' - open_bookmark :console, 'MyProject Console' - - project_dir.select - end - - @window.concatenated_buffer.should == desired - end - end - - describe "switching between tabs (example 4)" do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should generate and run the correct Applescript" do - desired = (<<-CMD).strip -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 - open_tab :first_tab - open_tab :second_tab - first_tab.select do - write 'cd ~/projects' - write 'ls' - end - second_tab.write "echo 'hello there!'" - first_tab.select - end - - @window.concatenated_buffer.should == desired - end - end - - describe 'magic commands' do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should cd to the directory for the tab" do - @window.expects(:shell_out) - - ItermWindow.open do - open_tab :first_tab do - bundle "exec guard" - end - end - - @window.concatenated_buffer.should match(/write text "bundle exec guard"/) - end - end - - describe 'default tab' do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should mark the tab as the default tab" do - @window.expects(:shell_out) - - ItermWindow.open do - open_tab :first_tab, :default => true do - end - end - - @window.concatenated_buffer.should match(/select session id first_tab_tty/) - end - - it "should mark the tab as the default tab" do - @window.expects(:shell_out) - - ItermWindow.open do - default_tab :first_tab do - end - end - - @window.concatenated_buffer.should match(/select session id first_tab_tty/) - end - end - - describe 'change directory' do - before(:each) do - ItermWindow.expects(:new).returns(@window) - end - - it "should cd to the directory for the tab" do - @window.expects(:shell_out) - - ItermWindow.open do - open_tab :first_tab, :dir => 'my-dir' do - end - end - - @window.concatenated_buffer.should match(/cd my-dir/) - end - - it "should cd to the directry for all tabs" do - @window.expects(:shell_out) - - ItermWindow.open :dir => 'my-dir' do - open_tab :first_tab do - end - end - - @window.concatenated_buffer.should match(/cd my-dir/) - 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 - - it 'should generate color in a tab definition' do - @window.expects(:shell_out) - ItermWindow::Tab.any_instance.expects(:create_tab_color_file).with("FF00AA") - - ItermWindow.open do - open_tab :first_tab, :color => "FF00AA" do - end - end - end - - it 'should use predetermined colors' do - @window.expects(:shell_out) - ItermWindow::Tab.any_instance.expects(:create_tab_color_file).with(:rails) - - ItermWindow.open do - open_tab :first_tab, :color => :rails do - 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