Skip to content
Browse files

Merge branch 'f-004-tmux'

  • Loading branch information...
2 parents 7de9d68 + a99961a commit 0533958c2d09a89857c699508c43d642b7dd6712 @hipe committed Jan 24, 2012
Showing with 294 additions and 269 deletions.
  1. +9 −0 CHANGELOG.md
  2. +167 −153 lib/myterm/api.rb
  3. +118 −116 lib/myterm/cli.rb
View
9 CHANGELOG.md
@@ -0,0 +1,9 @@
+
+
+## for version 0.0.4 -
+
+### 2012-01-20
+
+ * fix issue with tmux sessions
+ * overhaul whitespace & naming conventions
+
View
320 lib/myterm/api.rb
@@ -1,194 +1,208 @@
-module Skylab
- module Myterm
- def self.version
- File.read(File.expand_path('../../../VERSION', __FILE__))
+module Skylab; end
+
+module Skylab::Myterm
+
+ class ValidationError < RuntimeError ; end
+
+ module Color
+ def alpha= mixed
+ if mixed.kind_of?(String)
+ md = /\A(\d+(?:\.\d+)?)%?\z/.match(mixed) or
+ raise ValidationError.new("invalid format for percent #{val.inspect} -- expecting e.g. \"58%\"")
+ mixed = md[1].to_f
+ end
+ (0.0..100.0).include?(mixed) or
+ raise ValidationError.new("Percent value (#{mixed}%) must be between 0 and 100 inclusive.")
+ self[3] = ChannelScalarNormalized[mixed / 100.0]
end
- end
-end
-class Skylab::Myterm::ValidationError < RuntimeError ; end
+ def to_hex
+ '#' + self.map{ |x| int_to_hex(x) }.join('')
+ end
-module Skylab::Myterm::Color
- Myterm = Skylab::Myterm
- def self.[] obj
- obj.extend self
- end
- def self.dup color
- self[color.dup]
- end
- def alpha= mixed
- if mixed.kind_of?(String)
- md = /\A(\d+(?:\.\d+)?)%?\z/.match(mixed) or
- raise Myterm::ValidationError.new("invalid format for percent #{val.inspect} -- expecting e.g. \"58%\"")
- mixed = md[1].to_f
- end
- (0.0..100.0).include?(mixed) or
- raise Myterm::ValidationError.new("Percent value (#{mixed}%) must be between 0 and 100 inclusive.")
- self[3] = Myterm::ChannelScalarNormalized[mixed / 100.0]
+ TARGET_PLACES = 2 # each component of an #rrggbb hexadecimal color has 2 places
+
+ DIVISOR = 16 ** TARGET_PLACES
+
+ def int_to_hex int
+ int.respond_to?(:to_hex) and return int.to_hex
+ (int.to_f / DIVISOR).round.to_s(16).rjust(TARGET_PLACES, '0')
+ end
end
- def to_hex
- '#' + self.map{ |x| int_to_hex(x) }.join('')
+
+ class << Color
+ def [] obj
+ obj.extend self
+ end
+
+ def dup color
+ self[color.dup]
+ end
end
- TargetPlaces = 2 # each component of an #rrggbb hexadecimal color has 2 places
- Divisor = 16 ** TargetPlaces
- def int_to_hex int
- int.respond_to?(:to_hex) and return int.to_hex
- (int.to_f / Divisor).round.to_s(16).rjust(TargetPlaces, '0')
+
+ module ChannelScalarNormalized
+ def to_hex
+ (('ff'.to_i(16).to_f * self).to_i).to_s(16).rjust(2, '0')
+ end
end
-end
-module Skylab::Myterm::ChannelScalarNormalized
- def self.[] obj
- obj.extend self
+ class << ChannelScalarNormalized
+ def [] obj
+ obj.extend self
+ end
end
- def to_hex
- (('ff'.to_i(16).to_f * self).to_i).to_s(16).rjust(2, '0')
+
+ class ImageBuilder
+ def build_text_drawing img
+ @lines.empty? and return fail("foo")
+ #@todo setters for everything etc
+ draw = Magick::Draw.new
+ draw.gravity = @opts[:gravity] || Magick::NorthEastGravity
+ @opts[:fill] ||= '#662020'
+ @opts[:fill].kind_of?(Proc) and @opts[:fill] = @opts[:fill].call(self)
+ draw.fill = @opts[:fill]
+ draw.font = @opts[:font] || "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
+ draw.font_style = @opts[:font_style] || Magick::NormalStyle
+ draw.pointsize = @opts[:point_size] || 60
+ draw.text_antialias = @opts.key?(:text_antialias) ? @opts[:text_antialias] : true
+ draw.annotate(img, 0,0,20,10, @lines.first)
+ if @lines.length > 1
+ second_line = @lines[1..-1].join(' ')
+ draw.annotate(img, 0,0,20,80, second_line) do
+ self.pointsize = 30
+ end
+ end
+ nil # draw not needed at this point
+ end
+ private :build_text_drawing
+
+ def initialize iterm, lines, opts
+ @iterm, @lines, @opts = [iterm, lines, opts]
+ end
+
+ attr_reader :iterm
+
+ def run
+ require 'RMagick'
+ bg_color = Color.dup(@iterm.session.background_color)
+ @opts.key?(:alpha_percent) and bg_color.alpha = @opts[:alpha_percent]
+ img = Magick::Image.new(500, 300) do # copying over hard-coded dimensions from original Dmytro script
+ self.background_color = bg_color.to_hex
+ end
+ build_text_drawing img
+ img
+ end
end
-end
-class Skylab::Myterm::ImageBuilder
- Myterm = Skylab::Myterm
- class << self
+ class << ImageBuilder
def build_background_image iterm, lines, opts
new(iterm, lines, opts).run
end
end
- def initialize iterm, lines, opts
- @iterm, @lines, @opts = [iterm, lines, opts]
- end
- attr_reader :iterm
- def run
- require 'RMagick'
- bg_color = Myterm::Color.dup(@iterm.session.background_color)
- @opts.key?(:alpha_percent) and bg_color.alpha = @opts[:alpha_percent]
- img = Magick::Image.new(500, 300) do # copying over hard-coded dimensions from original Dmytro script
- self.background_color = bg_color.to_hex
- end
- build_text_drawing img
- img
- end
-private
- def build_text_drawing img
- @lines.empty? and return fail("foo")
- #@todo setters for everything etc
- draw = Magick::Draw.new
- draw.gravity = @opts[:gravity] || Magick::NorthEastGravity
- @opts[:fill] ||= '#662020'
- @opts[:fill].kind_of?(Proc) and @opts[:fill] = @opts[:fill].call(self)
- draw.fill = @opts[:fill]
- draw.font = @opts[:font] || "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
- draw.font_style = @opts[:font_style] || Magick::NormalStyle
- draw.pointsize = @opts[:point_size] || 60
- draw.text_antialias = @opts.key?(:text_antialias) ? @opts[:text_antialias] : true
- draw.annotate(img, 0,0,20,10, @lines.first)
- if @lines.length > 1
- second_line = @lines[1..-1].join(' ')
- draw.annotate(img, 0,0,20,80, second_line) do
- self.pointsize = 30
- end
- end
- nil # draw not needed at this point
- end
-end
-class Skylab::Myterm::ItermProxy
- # ItermProxy is a wrapper around everything Iterm to the extent that its AppleScript interface supports
+ class ItermProxy
+ # ItermProxy is a wrapper around everything Iterm to the extent that its AppleScript interface supports
+ #
+ MIN_LEN = 50
- Myterm = ::Skylab::Myterm # keep top level name out of the bulk of the code
+ def app
+ @app ||= begin
+ require 'appscript'
+ Appscript.app('iTerm')
+ end
+ end
+ private :app
- MinLen = 50
+ def invalid msg
+ raise ValidationError.new(msg)
+ end
+ private :invalid
- def bounds= arr
- x = arr.detect { |i| i.to_s !~ /^\d+$/ } and return invalid("expecting digit had #{x.inspect}")
- x = arr[2,2].detect { |i| i.to_i < MinLen } and return invalid("too small: #{x} (min: #{MinLen})")
- app.windows[0].bounds.set arr
- end
+ def bounds= arr
+ x = arr.detect { |i| i.to_s !~ /^\d+$/ } and return invalid("expecting digit had #{x.inspect}")
+ x = arr[2,2].detect { |i| i.to_i < MIN_LEN } and return invalid("too small: #{x} (min: #{MIN_LEN})")
+ app.windows[0].bounds.set arr
+ end
- def bounds
- app.windows[0].bounds.get
- end
+ def bounds
+ app.windows[0].bounds.get
+ end
- def session
- tty = `tty`.strip
- @session ||= begin
- session = catch(:catch_two) do
- app.terminals.get.each do |term|
- sessions = term.sessions.get
- sessions.each do |session|
- if session.tty.get == tty
- throw :catch_two, session
+ def session
+ @session ||= begin
+ tty = `tty`.strip
+ t = s = 0
+ catch(:break) do
+ (1..app.terminals.count).each do |i|
+ (1..app.terminals[i].sessions.count).each do |j|
+ if tty == app.terminals[i].sessions[j].tty.get
+ throw(:break, SessionProxy.new(app, i, j))
+ end
end
end
- end
+ nil
+ end or fail("couldn't ascertain current session!")
end
- session or fail("couldn't ascertain current session!")
- SessionProxy.new(session)
end
end
-private
-
- def app
- @app ||= begin
- require 'appscript'
- Appscript.app('iTerm')
+ module AppscriptDelegator
+ def delegated_attr_readers *list
+ list.each do |property|
+ lambda do |_property|
+ define_method(_property) do
+ resource.send(_property).get
+ end
+ end.call(property)
+ end
end
- end
- def invalid msg
- raise Myterm::ValidationError.new(msg)
- end
-end
+ def delegated_attr_writers *list
+ list.each do |property|
+ lambda do |_property|
+ define_method("#{_property}=") do |val|
+ resource.send(_property).set val
+ end
+ end.call(property)
+ end
+ end
-module Skylab::Myterm::AppscriptDelegator
- def delegated_attr_readers *list
- list.each do |property|
- lambda do |_property|
- define_method(_property) do
- @resource.send(_property).get
- end
- end.call(property)
+ def delegated_attr_accessors *list
+ delegated_attr_readers(*list)
+ delegated_attr_writers(*list)
end
end
- def delegated_attr_writers *list
- list.each do |property|
- lambda do |_property|
- define_method("#{_property}=") do |val|
- @resource.send(_property).set val
- end
- end.call(property)
+
+ class ItermProxy::SessionProxy
+ extend AppscriptDelegator
+
+ delegated_attr_accessors :background_image_path
+
+ def background_color
+ Color[resource.background_color.get]
end
- end
- def delegated_attr_accessors *list
- delegated_attr_readers(*list)
- delegated_attr_writers(*list)
- end
-end
-class Skylab::Myterm::ItermProxy::SessionProxy
- Myterm = Skylab::Myterm
- def initialize session
- @resource = session
- end
- extend Myterm::AppscriptDelegator
+ def foreground_color
+ Color[resource.foreground_color.get]
+ end
- delegated_attr_accessors :background_image_path
- delegated_attr_readers :tty
+ def initialize app, term_idx, session_idx
+ @app, @term_idx, @sessions_idx = [app, term_idx, session_idx]
+ end
- def background_color
- Myterm::Color[@resource.background_color.get]
- end
+ def resource
+ @app.terminals[@term_idx].sessions[@sessions_idx]
+ end
- def foreground_color
- Myterm::Color[@resource.foreground_color.get]
+ delegated_attr_readers :tty
end
end
-module Skylab::Myterm::ChannelScalarNormalized
- def self.[] obj
- obj.extend self
- end
- def to_hex
- (('ff'.to_i(16).to_f * self).to_i).to_s(16).rjust(2, '0')
+module Skylab
+ class << Myterm
+ def version
+ File.read(File.expand_path('../../../VERSION', __FILE__))
+ end
end
end
+
View
234 lib/myterm/cli.rb
@@ -2,141 +2,143 @@
require File.expand_path('../api', __FILE__)
require 'open3'
-module Skylab::Myterm::PathPrettifier
- HomeDirRe = /\A#{Regexp.escape(ENV['HOME'])}/
-protected
- def pretty_path path
- path.sub(HomeDirRe, '~')
+
+module Skylab::Myterm
+ module PathPrettifier
+ HOME_DIR_RE = /\A#{Regexp.escape(ENV['HOME'])}/
+ def pretty_path path
+ path.sub(HOME_DIR_RE, '~')
+ end
end
-end
-class Skylab::Face::Command
- include Skylab::Myterm::PathPrettifier
-end
+ class ::Skylab::Face::Command
+ include PathPrettifier # eew
+ end
-class Skylab::Myterm::Cli < Skylab::Face::Cli
- Myterm = ::Skylab::Myterm # don't use fully qualified name internally
- include Myterm::PathPrettifier
+ class Cli < ::Skylab::Face::Cli
+ include PathPrettifier
- version { Skylab::Myterm.version}
+ version { ::Skylab::Myterm.version }
- o(:bounds) do |o|
- syntax "#{invocation_string} [x y width height]"
- o.banner = "gets/sets the bounds of the terminal window\n#{usage_string}"
- end
+ o(:bounds) do |o|
+ syntax "#{invocation_string} [x y width height]"
+ o.banner = "gets/sets the bounds of the terminal window\n#{usage_string}"
+ end
- def bounds o, *a
- case a.length
- when 4
- begin ; iterm.bounds = a ; rescue Myterm::ValidationError => e ; return usage e ; end
- when 0
- @err.puts iterm.bounds.inspect
- else
- return usage("bad number of args #{a.length}: expecting 0 or 4")
+ def bounds o, *a
+ case a.length
+ when 4
+ begin ; iterm.bounds = a ; rescue ValidationError => e ; return usage e ; end
+ when 0
+ @err.puts iterm.bounds.inspect
+ else
+ return usage("bad number of args #{a.length}: expecting 0 or 4")
+ end
end
- end
- o(:'bg') do |o, req|
- syntax "#{invocation_string} [opts] [<text> [<text> [...]]]"
- o.banner = "Generate a background image with certain text for the terminal\n#{usage_string}"
- o.on('-e', '--exec <cmd ...>', 'Execute <cmd ...> in shell, also use it as text for background.') { }
- o.on('-o', '--opacity PERCENT', "Percent by which to make image background opaque",
- "(0%: tranparent. 100%: solid. Default: solid)") { |amt| req[:alpha_percent] = amt }
- req[:font_file] = DefaultFontFile
- o.on('--font FONTFILE.ttf', "font to use (default: #{pretty_path(req[:font_file])})") do |path|
- req[:font_file] = path
+ o(:'bg') do |o, req|
+ syntax "#{invocation_string} [opts] [<text> [<text> [...]]]"
+ o.banner = "Generate a background image with certain text for the terminal\n#{usage_string}"
+ o.on('-e', '--exec <cmd ...>', 'Execute <cmd ...> in shell, also use it as text for background.') { }
+ o.on('-o', '--opacity PERCENT', "Percent by which to make image background opaque",
+ "(0%: tranparent. 100%: solid. Default: solid)") { |amt| req[:alpha_percent] = amt }
+ req[:font_file] = DEFAULT_FONT_FILE
+ o.on('--font FONTFILE.ttf', "font to use (default: #{pretty_path(req[:font_file])})") do |path|
+ req[:font_file] = path
+ end
+ req[:fill] = '#662020'
+ o.on('--fill[=COLOR]', "Write text in this color (default: #{req[:fill].inspect})",
+ "(when present but with no value, will use \"Text/Normal\" setting of current iTerm tab)" ) do |v|
+ req[:fill] = v || lambda { |img| img.iterm.session.foreground_color.to_hex }
+ end
+ o.on('-v', '--verbose', 'Be verbose.') { req[:verbose] = true }
end
- req[:fill] = '#662020'
- o.on('--fill[=COLOR]', "Write text in this color (default: #{req[:fill].inspect})",
- "(when present but with no value, will use \"Text/Normal\" setting of current iTerm tab)" ) do |v|
- req[:fill] = v || lambda { |img| img.iterm.session.foreground_color.to_hex }
+
+ def before_parse_bg req, args
+ idx = args.index { |s| %w(-e --exec).include?(s) } or return true
+ req[:_exec_this] = args[(idx+1)..-1]
+ args.replace idx == 0 ? [] : args[0..(idx-1)]
+ true
+ end
+ protected :before_parse_bg
+
+ def bg req, *args
+ if args.empty?
+ if req[:_exec_this]
+ args.any? and fail("logic error -- see before_parse_bg.")
+ args = req[:_exec_this]
+ else
+ return get_background
+ end
+ end
+ check_font(req) or return
+ img = ImageBuilder.build_background_image(iterm, args, req) or return false
+ req[:verbose] and @err.puts "(bg_color: #{img.background_color.inspect})"
+ outpath = "#{IMG_DIRNAME}/#{IMG_BASENAME}.#{Process.pid}.png"
+ img.write(outpath)
+ req[:verbose] and @err.puts "(setting background image to: #{outpath})" # doesn't care if --verbose
+ iterm.session.background_image_path = outpath
+ if req[:_exec_this]
+ @err.puts "(#{program_name} executing: #{req[:_exec_this].join(' ')})"
+ exec(req[:_exec_this].join(' '))
+ end
+ true
end
- o.on('-v', '--verbose', 'Be verbose.') { req[:verbose] = true }
- end
- def before_parse_bg req, args
- idx = args.index { |s| %w(-e --exec).include?(s) } or return true
- req[:_exec_this] = args[(idx+1)..-1]
- args.replace idx == 0 ? [] : args[0..(idx-1)]
- true
- end
- protected :before_parse_bg
+ DEFAULT_FONT_FILE = "#{ENV['HOME']}/.fonts/MytermDefaultFont.ttf"
+ IMG_DIRNAME = '/tmp'
+ IMG_BASENAME = 'iTermBG'
- def bg req, *args
- if args.empty?
- if req[:_exec_this]
- args.any? and fail("logic error -- see before_parse_bg.")
- args = req[:_exec_this]
+ private
+
+ def check_font req
+ File.exist?(req[:font_file]) and return true
+ if req[:font_file] == DEFAULT_FONT_FILE
+ return maybe_download_font req
else
- return get_background
+ font_not_found req
end
end
- check_font(req) or return
- img = Myterm::ImageBuilder.build_background_image(iterm, args, req) or return false
- req[:verbose] and @err.puts "(bg_color: #{img.background_color.inspect})"
- outpath = "#{ImgDirname}/#{ImgBasename}.#{Process.pid}.png"
- img.write(outpath)
- req[:verbose] and @err.puts "(setting background image to: #{outpath})" # doesn't care if --verbose
- iterm.session.background_image_path = outpath
- if req[:_exec_this]
- @err.puts "(#{program_name} executing: #{req[:_exec_this].join(' ')})"
- exec(req[:_exec_this].join(' '))
- end
- true
- end
- DefaultFontFile = "#{ENV['HOME']}/.fonts/MytermDefaultFont.ttf"
- ImgDirname = '/tmp'
- ImgBasename = 'iTermBG'
-
-private
- def check_font req
- File.exist?(req[:font_file]) and return true
- if req[:font_file] == DefaultFontFile
- return maybe_download_font req
- else
- font_not_found req
+ DEFAULT_FONT_URL = 'http://img.dafont.com/dl/?f=simple_life'
+ DEFAULT_FONT_FILE_NOT_SIMLINKED = "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
+
+ def maybe_download_font req
+ target = DEFAULT_FONT_FILE_NOT_SIMLINKED
+ File.exist?(target) and return true
+ $stdin.tty? && $stdout.tty? or return font_not_found(req)
+ @err.write "Font file #{pretty_path(req[:font_file])} not found. "
+ require 'highline'
+ require 'fileutils'
+ HighLine.new.agree("Let #{program_name} download it? (Y/n) (recommended: yes)") or return false
+ outfile = DEFAULT_FONT_FILE_NOT_SIMLINKED.sub(/\.ttf$/, '.zip')
+ font_dir = File.dirname(outfile)
+ File.directory?(font_dir) or FileUtils.mkdir_p(font_dir, :verbose => true)
+ cmds = ["wget -O #{outfile} #{DEFAULT_FONT_URL}"]
+ cmds.push "cd #{font_dir}"
+ cmds.push "unzip #{outfile}"
+ cmds.push "ln -s #{DEFAULT_FONT_FILE_NOT_SIMLINKED} #{DEFAULT_FONT_FILE}"
+ cmds.push("echo 'finished installing for #{program_name}: #{pretty_path(DEFAULT_FONT_FILE_NOT_SIMLINKED)}. " <<
+ "Please try using it again.'")
+ @err.puts(cmd = cmds.join(' ; '))
+ exec(cmd)
end
- end
-
- DefaultFontUrl = 'http://img.dafont.com/dl/?f=simple_life'
- DefaultFontFileNotSimlinked = "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
-
- def maybe_download_font req
- target = DefaultFontFileNotSimlinked
- File.exist?(target) and return true
- $stdin.tty? && $stdout.tty? or return font_not_found(req)
- @err.write "Font file #{pretty_path(req[:font_file])} not found. "
- require 'highline'
- require 'fileutils'
- HighLine.new.agree("Let #{program_name} download it? (Y/n) (recommended: yes)") or return false
- outfile = DefaultFontFileNotSimlinked.sub(/\.ttf$/, '.zip')
- font_dir = File.dirname(outfile)
- File.directory?(font_dir) or FileUtils.mkdir_p(font_dir, :verbose => true)
- cmds = ["wget -O #{outfile} #{DefaultFontUrl}"]
- cmds.push "cd #{font_dir}"
- cmds.push "unzip #{outfile}"
- cmds.push "ln -s #{DefaultFontFileNotSimlinked} #{DefaultFontFile}"
- cmds.push("echo 'finished installing for #{program_name}: #{pretty_path(DefaultFontFileNotSimlinked)}. " <<
- "Please try using it again.'")
- @err.puts(cmd = cmds.join(' ; '))
- exec(cmd)
- end
- def font_not_found req
- @err.puts "font file not found: #{pretty_path(req[:font_file])}"
- req.command.usage
- return false
- end
+ def font_not_found req
+ @err.puts "font file not found: #{pretty_path(req[:font_file])}"
+ req.command.usage
+ return false
+ end
- def iterm
- @iterm ||= Myterm::ItermProxy.new
- end
+ def iterm
+ @iterm ||= ItermProxy.new
+ end
- def get_background
- @err.puts "tty: #{iterm.session.tty}"
- @err.puts "background_image: #{iterm.session.background_image_path.inspect}"
- @err.puts "background_color: #{iterm.session.background_color}"
+ def get_background
+ @err.puts "tty: #{iterm.session.tty}"
+ @err.puts "background_image: #{iterm.session.background_image_path.inspect}"
+ @err.puts "background_color: #{iterm.session.background_color}"
+ end
end
-
end
+

0 comments on commit 0533958

Please sign in to comment.
Something went wrong with that request. Please try again.