myterm 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/._repath.rb +54 -0
- data/.gitignore +3 -0
- data/.repath.sh +4 -0
- data/.rvmrc.example +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +33 -0
- data/README.md +56 -0
- data/bin/myterm +5 -0
- data/doc/HISTORY.md +17 -0
- data/lib/myterm/api.rb +189 -0
- data/lib/myterm/cli.rb +149 -0
- data/lib/myterm/vendor/face/cli.rb +391 -0
- data/lib/myterm/version.rb +4 -0
- data/lib-iterm.sh +163 -0
- data/myterm.gemspec +25 -0
- metadata +98 -0
data/._repath.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
payload = lambda do
|
4
|
+
|
5
|
+
bin_folder="#{`pwd`.strip}/bin"
|
6
|
+
unless File.directory?(bin_folder)
|
7
|
+
return {
|
8
|
+
:message => "not a directory, won't add to PATH: #{bin_folder}"
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
path = ENV['PATH']
|
13
|
+
path_parts = path.split(':')
|
14
|
+
|
15
|
+
if path.include?(bin_folder)
|
16
|
+
if true or ARGV.include?('-F')
|
17
|
+
unless path_parts.reject! { |p| p == bin_folder }
|
18
|
+
return {
|
19
|
+
:message => "bin folder \"#{bin_folder}\" not found in path \"#{path}\""
|
20
|
+
}
|
21
|
+
end
|
22
|
+
return {
|
23
|
+
:new_path => ( [bin_folder] + [path_parts] ).join(':'),
|
24
|
+
:message => "rewriting path to have bin folder at the beginning",
|
25
|
+
:success => true
|
26
|
+
}
|
27
|
+
else
|
28
|
+
if 0 == path.index(bin_folder)
|
29
|
+
return {
|
30
|
+
:message => "bin folder is already at front of PATH",
|
31
|
+
:success => true
|
32
|
+
}
|
33
|
+
else
|
34
|
+
return {
|
35
|
+
:message => "bin folder is in path but not at front. use -F to rewrite PATH",
|
36
|
+
:status => :not_front,
|
37
|
+
:success => true
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else
|
42
|
+
path_parts.unshift(bin_folder)
|
43
|
+
return {
|
44
|
+
:new_path => path_parts.join(':'),
|
45
|
+
:message => "prepending bin folder to the beginning of the PATH.",
|
46
|
+
:success => true
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
end.call
|
51
|
+
|
52
|
+
payload[:message] and $stdout.puts "echo #{payload[:message].inspect}"
|
53
|
+
payload[:new_path] and $stdout.puts "export PATH=\"#{payload[:new_path]}\""
|
54
|
+
$stdout.puts(payload[:success] ? "echo 'hack done.'" : "echo 'hack failed.'")
|
data/.gitignore
ADDED
data/.repath.sh
ADDED
data/.rvmrc.example
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@skylab
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
myterm (0.0.1)
|
5
|
+
highline
|
6
|
+
rb-appscript
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
archive-tar-minitar (0.5.2)
|
12
|
+
columnize (0.3.4)
|
13
|
+
highline (1.6.2)
|
14
|
+
linecache19 (0.5.12)
|
15
|
+
ruby_core_source (>= 0.1.4)
|
16
|
+
rb-appscript (0.6.1)
|
17
|
+
ruby-debug-base19 (0.11.25)
|
18
|
+
columnize (>= 0.3.1)
|
19
|
+
linecache19 (>= 0.5.11)
|
20
|
+
ruby_core_source (>= 0.1.4)
|
21
|
+
ruby-debug19 (0.11.6)
|
22
|
+
columnize (>= 0.3.1)
|
23
|
+
linecache19 (>= 0.5.11)
|
24
|
+
ruby-debug-base19 (>= 0.11.19)
|
25
|
+
ruby_core_source (0.1.5)
|
26
|
+
archive-tar-minitar (>= 0.5.2)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
myterm!
|
33
|
+
ruby-debug19
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# myterm
|
2
|
+
|
3
|
+
### _(command line api for playing with iTerm)_
|
4
|
+
|
5
|
+
## About
|
6
|
+
|
7
|
+
`myterm` is a command line interface for customizing iTerm using AppleScript. Its most useful feature is that it can throw up a big message in the background of your terminal tab to tell you clearly which tab it is.
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
`myterm` attempts to be as self-documenting as possible. Try `myterm -h` for help.
|
15
|
+
|
16
|
+
The most common use case for me personally is something like:
|
17
|
+
|
18
|
+
myterm bg --exec node server.js
|
19
|
+
|
20
|
+
which will display the string "node server.js" up in the background and then run that.
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
## Requirements
|
26
|
+
|
27
|
+
`myterm` needs ImageMagick and its `convert` executable to be in your path.
|
28
|
+
|
29
|
+
`myterm` needs some font file to use. It has an installer that will try to grab the [Simple Life](http://www.dafont.com/simple-life.font) font by Michael Strobel.
|
30
|
+
|
31
|
+
Additionally it needs whatever its gem dependencie(s) are, which at the time of this writing are: rb-appscript, highline.
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
|
38
|
+
`myterm` is a rubygem. If you are installing it from a git checkout
|
39
|
+
(which at the time of this writing is the only way to install it):
|
40
|
+
|
41
|
+
mkdir ~/src; cd ~/src
|
42
|
+
git clone git@github.com:hipe/myterm.git; cd myterm
|
43
|
+
gem build *.gemspec
|
44
|
+
gem install *.gem
|
45
|
+
|
46
|
+
|
47
|
+
## Support
|
48
|
+
|
49
|
+
I want this to work for you. Please contact me via email if it does not!
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
## Credits
|
55
|
+
|
56
|
+
`myterm` started life as an adaptation of Dmytro Shteflyuk's script that he used at Scribd as described [here](http://kpumuk.info/mac-os-x/how-to-show-ssh-host-name-on-the-iterms-background/). Thank you Dmytro!
|
data/bin/myterm
ADDED
data/doc/HISTORY.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# myterm Change History
|
2
|
+
|
3
|
+
## Release 0.0.3 - 2011-08-06
|
4
|
+
|
5
|
+
* fix issue with transparency - didn't make refactor
|
6
|
+
|
7
|
+
|
8
|
+
## Relelase 0.0.2 - 2011-08-04
|
9
|
+
|
10
|
+
* Add installer for default font file when none is found
|
11
|
+
* Optionally use iTerm foreground color for background image foreground color
|
12
|
+
* Total refactor of code: separated into a 'CLI' and an 'API'
|
13
|
+
|
14
|
+
|
15
|
+
## Release 0.0.1
|
16
|
+
|
17
|
+
* initial release, creates background images
|
data/lib/myterm/api.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
module Skylab; end
|
2
|
+
module Skylab::Myterm; end
|
3
|
+
|
4
|
+
class Skylab::Myterm::ValidationError < RuntimeError ; end
|
5
|
+
|
6
|
+
module Skylab::Myterm::Color
|
7
|
+
Myterm = Skylab::Myterm
|
8
|
+
def self.[] obj
|
9
|
+
obj.extend self
|
10
|
+
end
|
11
|
+
def self.dup color
|
12
|
+
self[color.dup]
|
13
|
+
end
|
14
|
+
def alpha= mixed
|
15
|
+
if mixed.kind_of?(String)
|
16
|
+
md = /\A(\d+(?:\.\d+)?)%?\z/.match(mixed) or
|
17
|
+
raise Myterm::ValidationError.new("invalid format for percent #{val.inspect} -- expecting e.g. \"58%\"")
|
18
|
+
mixed = md[1].to_f
|
19
|
+
end
|
20
|
+
(0.0..100.0).include?(mixed) or
|
21
|
+
raise Myterm::ValidationError.new("Percent value (#{mixed}%) must be between 0 and 100 inclusive.")
|
22
|
+
self[3] = Myterm::ChannelScalarNormalized[mixed / 100.0]
|
23
|
+
end
|
24
|
+
def to_hex
|
25
|
+
'#' + self.map{ |x| int_to_hex(x) }.join('')
|
26
|
+
end
|
27
|
+
TargetPlaces = 2 # each component of an #rrggbb hexadecimal color has 2 places
|
28
|
+
Divisor = 16 ** TargetPlaces
|
29
|
+
def int_to_hex int
|
30
|
+
int.respond_to?(:to_hex) and return int.to_hex
|
31
|
+
(int.to_f / Divisor).round.to_s(16).rjust(TargetPlaces, '0')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Skylab::Myterm::ChannelScalarNormalized
|
36
|
+
def self.[] obj
|
37
|
+
obj.extend self
|
38
|
+
end
|
39
|
+
def to_hex
|
40
|
+
(('ff'.to_i(16).to_f * self).to_i).to_s(16).rjust(2, '0')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Skylab::Myterm::ImageBuilder
|
45
|
+
Myterm = Skylab::Myterm
|
46
|
+
class << self
|
47
|
+
def build_background_image iterm, lines, opts
|
48
|
+
new(iterm, lines, opts).run
|
49
|
+
end
|
50
|
+
end
|
51
|
+
def initialize iterm, lines, opts
|
52
|
+
@iterm, @lines, @opts = [iterm, lines, opts]
|
53
|
+
end
|
54
|
+
attr_reader :iterm
|
55
|
+
def run
|
56
|
+
require 'RMagick'
|
57
|
+
bg_color = Myterm::Color.dup(@iterm.session.background_color)
|
58
|
+
@opts.key?(:alpha_percent) and bg_color.alpha = @opts[:alpha_percent]
|
59
|
+
img = Magick::Image.new(500, 300) do # copying over hard-coded dimensions from original Dmytro script
|
60
|
+
self.background_color = bg_color.to_hex
|
61
|
+
end
|
62
|
+
build_text_drawing img
|
63
|
+
img
|
64
|
+
end
|
65
|
+
private
|
66
|
+
def build_text_drawing img
|
67
|
+
@lines.empty? and return fail("foo")
|
68
|
+
#@todo setters for everything etc
|
69
|
+
draw = Magick::Draw.new
|
70
|
+
draw.gravity = @opts[:gravity] || Magick::NorthEastGravity
|
71
|
+
@opts[:fill] ||= '#662020'
|
72
|
+
@opts[:fill].kind_of?(Proc) and @opts[:fill] = @opts[:fill].call(self)
|
73
|
+
draw.fill = @opts[:fill]
|
74
|
+
draw.font = @opts[:font] || "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
|
75
|
+
draw.font_style = @opts[:font_style] || Magick::NormalStyle
|
76
|
+
draw.pointsize = @opts[:point_size] || 60
|
77
|
+
draw.text_antialias = @opts.key?(:text_antialias) ? @opts[:text_antialias] : true
|
78
|
+
draw.annotate(img, 0,0,20,10, @lines.first)
|
79
|
+
if @lines.length > 1
|
80
|
+
second_line = @lines[1..-1].join(' ')
|
81
|
+
draw.annotate(img, 0,0,20,80, second_line) do
|
82
|
+
self.pointsize = 30
|
83
|
+
end
|
84
|
+
end
|
85
|
+
nil # draw not needed at this point
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Skylab::Myterm::ItermProxy
|
90
|
+
# ItermProxy is a wrapper around everything Iterm to the extent that its AppleScript interface supports
|
91
|
+
|
92
|
+
Myterm = ::Skylab::Myterm # keep top level name out of the bulk of the code
|
93
|
+
|
94
|
+
MinLen = 50
|
95
|
+
|
96
|
+
def bounds= arr
|
97
|
+
x = arr.detect { |i| i.to_s !~ /^\d+$/ } and return invalid("expecting digit had #{x.inspect}")
|
98
|
+
x = arr[2,2].detect { |i| i.to_i < MinLen } and return invalid("too small: #{x} (min: #{MinLen})")
|
99
|
+
app.windows[0].bounds.set arr
|
100
|
+
end
|
101
|
+
|
102
|
+
def bounds
|
103
|
+
app.windows[0].bounds.get
|
104
|
+
end
|
105
|
+
|
106
|
+
def session
|
107
|
+
tty = `tty`.strip
|
108
|
+
@session ||= begin
|
109
|
+
session = catch(:catch_two) do
|
110
|
+
app.terminals.get.each do |term|
|
111
|
+
sessions = term.sessions.get
|
112
|
+
sessions.each do |session|
|
113
|
+
if session.tty.get == tty
|
114
|
+
throw :catch_two, session
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
session or fail("couldn't ascertain current session!")
|
120
|
+
SessionProxy.new(session)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def app
|
127
|
+
@app ||= begin
|
128
|
+
require 'appscript'
|
129
|
+
Appscript.app('iTerm')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def invalid msg
|
134
|
+
raise Myterm::ValidationError.new(msg)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
module Skylab::Myterm::AppscriptDelegator
|
139
|
+
def delegated_attr_readers *list
|
140
|
+
list.each do |property|
|
141
|
+
lambda do |_property|
|
142
|
+
define_method(_property) do
|
143
|
+
@resource.send(_property).get
|
144
|
+
end
|
145
|
+
end.call(property)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
def delegated_attr_writers *list
|
149
|
+
list.each do |property|
|
150
|
+
lambda do |_property|
|
151
|
+
define_method("#{_property}=") do |val|
|
152
|
+
@resource.send(_property).set val
|
153
|
+
end
|
154
|
+
end.call(property)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
def delegated_attr_accessors *list
|
158
|
+
delegated_attr_readers(*list)
|
159
|
+
delegated_attr_writers(*list)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class Skylab::Myterm::ItermProxy::SessionProxy
|
164
|
+
Myterm = Skylab::Myterm
|
165
|
+
def initialize session
|
166
|
+
@resource = session
|
167
|
+
end
|
168
|
+
extend Myterm::AppscriptDelegator
|
169
|
+
|
170
|
+
delegated_attr_accessors :background_image_path
|
171
|
+
delegated_attr_readers :tty
|
172
|
+
|
173
|
+
def background_color
|
174
|
+
Myterm::Color[@resource.background_color.get]
|
175
|
+
end
|
176
|
+
|
177
|
+
def foreground_color
|
178
|
+
Myterm::Color[@resource.foreground_color.get]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
module Skylab::Myterm::ChannelScalarNormalized
|
183
|
+
def self.[] obj
|
184
|
+
obj.extend self
|
185
|
+
end
|
186
|
+
def to_hex
|
187
|
+
(('ff'.to_i(16).to_f * self).to_i).to_s(16).rjust(2, '0')
|
188
|
+
end
|
189
|
+
end
|
data/lib/myterm/cli.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require "#{File.expand_path('../vendor/face/cli', __FILE__)}"
|
2
|
+
require "#{File.dirname(__FILE__)}/api"
|
3
|
+
require 'ruby-debug'
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
module Skylab; end
|
7
|
+
module Skylab::Myterm; end
|
8
|
+
|
9
|
+
module Skylab::Myterm::PathPrettifier
|
10
|
+
HomeDirRe = /\A#{Regexp.escape(ENV['HOME'])}/
|
11
|
+
protected
|
12
|
+
def pretty_path path
|
13
|
+
path.sub(HomeDirRe, '~')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Tmx::Face::Command
|
18
|
+
include Skylab::Myterm::PathPrettifier
|
19
|
+
end
|
20
|
+
|
21
|
+
class Skylab::Myterm::Cli < Tmx::Face::Cli
|
22
|
+
Myterm = ::Skylab::Myterm # don't use fully qualified name internally
|
23
|
+
include Myterm::PathPrettifier
|
24
|
+
|
25
|
+
version do
|
26
|
+
require "#{File.dirname(__FILE__)}/version"
|
27
|
+
Myterm::VERSION
|
28
|
+
end
|
29
|
+
|
30
|
+
o(:bounds) do |o|
|
31
|
+
syntax "#{path} [x y width height]"
|
32
|
+
o.banner = "gets/sets the bounds of the terminal window\n#{usage_string}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def bounds o, *a
|
36
|
+
case a.length
|
37
|
+
when 4
|
38
|
+
begin ; iterm.bounds = a ; rescue Myterm::ValidationError => e ; return usage e ; end
|
39
|
+
when 0
|
40
|
+
@err.puts iterm.bounds.inspect
|
41
|
+
else
|
42
|
+
return usage("bad number of args #{a.length}: expecting 0 or 4")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
o(:'bg') do |o, req|
|
47
|
+
syntax "#{path} [opts] [<text> [<text> [...]]]"
|
48
|
+
o.banner = "Generate a background image with certain text for the terminal\n#{usage_string}"
|
49
|
+
o.on('-e', '--exec <cmd ...>', 'Execute <cmd ...> in shell, also use it as text for background.') { }
|
50
|
+
o.on('-o', '--opacity PERCENT', "Percent by which to make image background opaque",
|
51
|
+
"(0%: tranparent. 100%: solid. Default: solid)") { |amt| req[:alpha_percent] = amt }
|
52
|
+
req[:font_file] = DefaultFontFile
|
53
|
+
o.on('--font FONTFILE.ttf', "font to use (default: #{pretty_path(req[:font_file])})") do |path|
|
54
|
+
req[:font_file] = path
|
55
|
+
end
|
56
|
+
req[:fill] = '#662020'
|
57
|
+
o.on('--fill[=COLOR]', "Write text in this color (default: #{req[:fill].inspect})",
|
58
|
+
"(when present but with no value, will use \"Text/Normal\" setting of current iTerm tab)" ) do |v|
|
59
|
+
req[:fill] = v || lambda { |img| img.iterm.session.foreground_color.to_hex }
|
60
|
+
end
|
61
|
+
o.on('-v', '--verbose', 'Be verbose.') { req[:verbose] = true }
|
62
|
+
end
|
63
|
+
|
64
|
+
def before_parse_bg req, args
|
65
|
+
idx = args.index { |s| %w(-e --exec).include?(s) } or return true
|
66
|
+
req[:_exec_this] = args[(idx+1)..-1]
|
67
|
+
args.replace idx == 0 ? [] : args[0..(idx-1)]
|
68
|
+
true
|
69
|
+
end
|
70
|
+
protected :before_parse_bg
|
71
|
+
|
72
|
+
def bg req, *args
|
73
|
+
if args.empty?
|
74
|
+
if req[:_exec_this]
|
75
|
+
args.any? and fail("logic error -- see before_parse_bg.")
|
76
|
+
args = req[:_exec_this]
|
77
|
+
else
|
78
|
+
return get_background
|
79
|
+
end
|
80
|
+
end
|
81
|
+
check_font(req) or return
|
82
|
+
img = Myterm::ImageBuilder.build_background_image(iterm, args, req) or return false
|
83
|
+
req[:verbose] and @err.puts "(bg_color: #{img.background_color.inspect})"
|
84
|
+
outpath = "#{ImgDirname}/#{ImgBasename}.#{Process.pid}.png"
|
85
|
+
img.write(outpath)
|
86
|
+
req[:verbose] and @err.puts "(setting background image to: #{outpath})" # doesn't care if --verbose
|
87
|
+
iterm.session.background_image_path = outpath
|
88
|
+
if req[:_exec_this]
|
89
|
+
@err.puts "(#{program_name} executing: #{req[:_exec_this].join(' ')})"
|
90
|
+
exec(req[:_exec_this].join(' '))
|
91
|
+
end
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
DefaultFontFile = "#{ENV['HOME']}/.fonts/MytermDefaultFont.ttf"
|
96
|
+
ImgDirname = '/tmp'
|
97
|
+
ImgBasename = 'iTermBG'
|
98
|
+
|
99
|
+
private
|
100
|
+
def check_font req
|
101
|
+
File.exist?(req[:font_file]) and return true
|
102
|
+
if req[:font_file] == DefaultFontFile
|
103
|
+
return maybe_download_font req
|
104
|
+
else
|
105
|
+
font_not_found req
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
DefaultFontUrl = 'http://img.dafont.com/dl/?f=simple_life'
|
110
|
+
DefaultFontFileNotSimlinked = "#{ENV['HOME']}/.fonts/SimpleLife.ttf"
|
111
|
+
|
112
|
+
def maybe_download_font req
|
113
|
+
target = DefaultFontFileNotSimlinked
|
114
|
+
File.exist?(target) and return true
|
115
|
+
$stdin.tty? && $stdout.tty? or return font_not_found(req)
|
116
|
+
@err.write "Font file #{pretty_path(req[:font_file])} not found. "
|
117
|
+
require 'highline'
|
118
|
+
require 'fileutils'
|
119
|
+
HighLine.new.agree("Let #{program_name} download it? (Y/n) (recommended: yes)") or return false
|
120
|
+
outfile = DefaultFontFileNotSimlinked.sub(/\.ttf$/, '.zip')
|
121
|
+
font_dir = File.dirname(outfile)
|
122
|
+
File.directory?(font_dir) or FileUtils.mkdir_p(font_dir, :verbose => true)
|
123
|
+
cmds = ["wget -O #{outfile} #{DefaultFontUrl}"]
|
124
|
+
cmds.push "cd #{font_dir}"
|
125
|
+
cmds.push "unzip #{outfile}"
|
126
|
+
cmds.push "ln -s #{DefaultFontFileNotSimlinked} #{DefaultFontFile}"
|
127
|
+
cmds.push("echo 'finished installing for #{program_name}: #{pretty_path(DefaultFontFileNotSimlinked)}. " <<
|
128
|
+
"Please try using it again.'")
|
129
|
+
@err.puts(cmd = cmds.join(' ; '))
|
130
|
+
exec(cmd)
|
131
|
+
end
|
132
|
+
|
133
|
+
def font_not_found req
|
134
|
+
@err.puts "font file not found: #{pretty_path(req[:font_file])}"
|
135
|
+
req.command.usage
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
|
139
|
+
def iterm
|
140
|
+
@iterm ||= Myterm::ItermProxy.new
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_background
|
144
|
+
@err.puts "tty: #{iterm.session.tty}"
|
145
|
+
@err.puts "background_image: #{iterm.session.background_image_path.inspect}"
|
146
|
+
@err.puts "background_color: #{iterm.session.background_color}"
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,391 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
# an ultralight command-line parser (391 lines)
|
4
|
+
# that wraps around OptParse (can do anything it does)
|
5
|
+
# with colors
|
6
|
+
# with flexible command-like options ('officious' like -v, -h)
|
7
|
+
# with commands with arguments based off of method signatures
|
8
|
+
# with subcommands, (namespaces) arbitrarily deeply nested
|
9
|
+
|
10
|
+
module Tmx; end
|
11
|
+
module Tmx::Face; end
|
12
|
+
|
13
|
+
module Tmx::Face::Colors
|
14
|
+
def bold str ; style str, :bright, :green end
|
15
|
+
def hi str ; style str, :green end
|
16
|
+
def ohno str ; style str, :red end
|
17
|
+
def yelo str ; style str, :yellow end
|
18
|
+
Styles = { :bright => 1, :red => 31, :yellow => 33, :green => 32, :cyan => 36 }
|
19
|
+
Esc = "\e" # "\u001b" ok in 1.9.2
|
20
|
+
def style str, *styles
|
21
|
+
nums = styles.map{ |o| o.kind_of?(Integer) ? o : Styles[o] }.compact
|
22
|
+
"#{Esc}[#{nums.join(';')}m#{str}#{Esc}[0m"
|
23
|
+
end
|
24
|
+
def highlight_header str
|
25
|
+
str.sub(/\A([^:]+:)/) { "#{hi($1)}" }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Tmx::Face
|
30
|
+
class Command
|
31
|
+
|
32
|
+
include Colors
|
33
|
+
|
34
|
+
def initialize name, *rest, &block
|
35
|
+
rest.any? and
|
36
|
+
raise ArgumentError.new("too many args for command: #{rest.inspect}")
|
37
|
+
@parser_definition = block # nil ok
|
38
|
+
@intern = name.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
alias_method :build, :new
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_option_parser req
|
46
|
+
parser = build_empty_option_parser
|
47
|
+
# we set the default value for the banner after we run the block
|
48
|
+
# to give the client the chance to set the syntax.
|
49
|
+
ugly, ugly_id = [parser.banner.dup, parser.banner.object_id]
|
50
|
+
if @parser_definition
|
51
|
+
args = [parser, req]
|
52
|
+
@parser_definition.arity > 0 and args = args[0, @parser_definition.arity]
|
53
|
+
instance_exec(*args, &@parser_definition)
|
54
|
+
end
|
55
|
+
if ugly == parser.banner && ugly_id = parser.banner.object_id
|
56
|
+
parser.banner = usage_string
|
57
|
+
end
|
58
|
+
parser
|
59
|
+
end
|
60
|
+
|
61
|
+
def for_run parent, name_as_used
|
62
|
+
self.parent = parent
|
63
|
+
@out = @parent.out
|
64
|
+
@err = @parent.err
|
65
|
+
@name_as_used = name_as_used
|
66
|
+
self # careful
|
67
|
+
end
|
68
|
+
|
69
|
+
def method
|
70
|
+
@parent.method method_symbol
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_symbol
|
74
|
+
@intern.to_s.downcase.gsub(/[^a-z0-9]+/, '_').intern
|
75
|
+
end
|
76
|
+
|
77
|
+
def name
|
78
|
+
@intern.to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse argv
|
82
|
+
req = { }
|
83
|
+
req.send(:instance_variable_set, '@method_parameters', argv)
|
84
|
+
class << req
|
85
|
+
attr_accessor :method_parameters, :command
|
86
|
+
end
|
87
|
+
@parent_protected_instance_methods.include?("before_parse_#{@intern}".intern) and
|
88
|
+
! @parent.send("before_parse_#{@intern}", req, argv) and return false
|
89
|
+
begin
|
90
|
+
build_option_parser(req).parse! argv
|
91
|
+
req
|
92
|
+
rescue OptionParser::ParseError => e
|
93
|
+
@out.puts highlight_header(e.to_s)
|
94
|
+
invite
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def summary
|
100
|
+
build_option_parser({}).to_s.
|
101
|
+
sub(/\A#{Regexp.escape(hi('usage:'))} /, '').
|
102
|
+
split("\n").select{ |s| ! s.strip.empty? }
|
103
|
+
end
|
104
|
+
|
105
|
+
def syntax *args
|
106
|
+
case args.length
|
107
|
+
when 0; @syntax ||= "#{invocation_string} [opts] [args]"
|
108
|
+
when 1; @syntax = args.first
|
109
|
+
else raise ArgumentError.new("expecting 0 or 1 argument")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def usage_string
|
114
|
+
"#{hi('usage:')} #{syntax}"
|
115
|
+
end
|
116
|
+
|
117
|
+
module Nodeish
|
118
|
+
def build_empty_option_parser
|
119
|
+
OptionParser.new
|
120
|
+
end
|
121
|
+
def invite
|
122
|
+
@err.puts "Try #{hi("#{invocation_string} -h")} for help."
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
def invocation_string
|
126
|
+
"#{@parent.invocation_string} #{name}"
|
127
|
+
end
|
128
|
+
alias_method :path, :invocation_string
|
129
|
+
def parent= parent
|
130
|
+
@parent and fail("won't overwrite existing parent")
|
131
|
+
@parent_protected_instance_methods = parent.class.protected_instance_methods(false).map(&:intern)
|
132
|
+
@parent = parent
|
133
|
+
end
|
134
|
+
def usage msg=nil
|
135
|
+
msg and @err.puts(msg)
|
136
|
+
@err.puts usage_string
|
137
|
+
invite
|
138
|
+
end
|
139
|
+
alias_method :empty_argv, :usage
|
140
|
+
end
|
141
|
+
include Nodeish
|
142
|
+
|
143
|
+
module TreeDefiner
|
144
|
+
def command_tree
|
145
|
+
@command_tree ||= begin
|
146
|
+
defined = command_definitions.map { |cls, a, b| cls.build(*a, &b) }
|
147
|
+
defined_m = defined.map(&:method_symbol).compact
|
148
|
+
implied_m = public_instance_methods(false).map(&:intern) - defined_m
|
149
|
+
implied = implied_m.map { |m| Command.new(m) }
|
150
|
+
Treeish[ defined + implied ]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
# this is nutty: for classes that extend this module, this is
|
154
|
+
# something that is triggered when they are subclasses
|
155
|
+
def inherited cls
|
156
|
+
cls.on('-h', '--help', 'show this screen') { help }
|
157
|
+
# You can rewrite the above in your class with another call to on()
|
158
|
+
# If you want to remove it, try:
|
159
|
+
# option_definitions.reject! { |a,_| '-h' == a.first }
|
160
|
+
end
|
161
|
+
def namespace name, &block
|
162
|
+
command_definitions.push [Namespace, [name], block]
|
163
|
+
end
|
164
|
+
def on *a, &b
|
165
|
+
block_given? or raise ArgumentError.new("block required")
|
166
|
+
option_definitions.push [a, b]
|
167
|
+
end
|
168
|
+
def option_definitions
|
169
|
+
@option_definitions ||= []
|
170
|
+
end
|
171
|
+
def command_definitions
|
172
|
+
@command_definitions ||= []
|
173
|
+
end
|
174
|
+
def method_added name
|
175
|
+
if @grab_next_method
|
176
|
+
command_definitions.last[1][0] = name.to_sym
|
177
|
+
@grab_next_method = false
|
178
|
+
end
|
179
|
+
end
|
180
|
+
def option_parser *a, &b
|
181
|
+
block_given? or raise ArgumentError.new("block required")
|
182
|
+
if a.empty?
|
183
|
+
@grab_next_method and fail("can't have two anonymous " <<
|
184
|
+
"command definitions in a row.")
|
185
|
+
@grab_next_method = true
|
186
|
+
a = [nil]
|
187
|
+
end
|
188
|
+
command_definitions.push [Command, a, b]
|
189
|
+
end
|
190
|
+
alias_method :o, :option_parser
|
191
|
+
end
|
192
|
+
|
193
|
+
module Treeish
|
194
|
+
def self.[] ary
|
195
|
+
ary.extend self
|
196
|
+
end
|
197
|
+
def ambiguous_command found, given
|
198
|
+
usage("Ambiguous command: #{given.inspect}. " <<
|
199
|
+
" Did you mean #{found.map{ |c| hi(c.name) }.join(' or ')}?")
|
200
|
+
end
|
201
|
+
def command_tree
|
202
|
+
@command_tree ||= begin
|
203
|
+
interface.command_tree.map { |c| c.parent = self; c } # careful
|
204
|
+
end
|
205
|
+
end
|
206
|
+
def expecting
|
207
|
+
interface.command_tree.map(&:name) * '|'
|
208
|
+
end
|
209
|
+
def find_command argv
|
210
|
+
argv.empty? and return empty_argv # should be just for n/s
|
211
|
+
given = argv.first
|
212
|
+
matcher = Regexp.new(/\A#{Regexp.escape(given)}/)
|
213
|
+
found = []
|
214
|
+
interface.command_tree.each do |cmd|
|
215
|
+
given == cmd.name and found = [cmd] and break
|
216
|
+
matcher.match(cmd.name) and found.push(cmd)
|
217
|
+
end
|
218
|
+
case found.size
|
219
|
+
when 0 ; unrecognized_command given
|
220
|
+
when 1 ; found.first.for_run(self, argv.shift)
|
221
|
+
else ; ambiguous_command found, given
|
222
|
+
end
|
223
|
+
end
|
224
|
+
Indent = ' '
|
225
|
+
def help
|
226
|
+
option_parser and @err.puts option_parser
|
227
|
+
cmds = command_tree
|
228
|
+
if cmds.any?
|
229
|
+
@err.puts hi('commands:')
|
230
|
+
rows = cmds.map { |c| { :name => c.name, :lines => c.summary } }
|
231
|
+
w = rows.map{ |d| d[:name].length }.inject(0){ |m, l| m > l ? m : l }
|
232
|
+
fmt = "%#{w}s "
|
233
|
+
rows.each do |row|
|
234
|
+
@out.puts "#{Indent}#{hi(fmt % row[:name])}#{row[:lines].first}"
|
235
|
+
row[:lines][1..-1].each do |line|
|
236
|
+
@out.puts "#{Indent}#{fmt % ''}#{line}"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
@err.puts("Try #{hi("#{invocation_string} [cmd] -h")} for command help.")
|
240
|
+
end
|
241
|
+
end
|
242
|
+
def option_parser
|
243
|
+
@option_parser.nil? or return @option_parser
|
244
|
+
op = build_empty_option_parser
|
245
|
+
op.banner = usage_string
|
246
|
+
if interface.option_definitions.any?
|
247
|
+
shorts = interface.option_definitions.map do |args, block|
|
248
|
+
op.on(*args) { instance_eval(&block) }
|
249
|
+
args.first
|
250
|
+
end
|
251
|
+
op.banner << "\n #{invocation_string} {#{shorts * '|'}}"
|
252
|
+
op.banner << "\n" << hi('options:')
|
253
|
+
end
|
254
|
+
@option_parser = op
|
255
|
+
end
|
256
|
+
def run_opts argv
|
257
|
+
begin
|
258
|
+
option_parser.parse! argv
|
259
|
+
rescue OptionParser::ParseError => e
|
260
|
+
@err.puts highlight_header(e.to_s)
|
261
|
+
invite
|
262
|
+
end
|
263
|
+
if argv.any?
|
264
|
+
@err.puts "(#{hi('ignoring:')} #{argv.map(&:inspect).join(', ')})"
|
265
|
+
end
|
266
|
+
true
|
267
|
+
end
|
268
|
+
def unrecognized_command given
|
269
|
+
usage("Unrecognized command: #{given.inspect}. Expecting: #{hi expecting}")
|
270
|
+
end
|
271
|
+
def usage_string
|
272
|
+
"#{hi('usage:')} #{invocation_string} " <<
|
273
|
+
"{#{interface.command_tree.map(&:name)*'|'}} [opts] [args]"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class Namespace
|
278
|
+
extend TreeDefiner, Colors
|
279
|
+
include Treeish, Nodeish, Colors
|
280
|
+
alias_method :interface, :class
|
281
|
+
def init_for_run parent, name_as_used
|
282
|
+
@name_as_used = name_as_used
|
283
|
+
@parent = parent
|
284
|
+
@out = @parent.out
|
285
|
+
@err = @parent.err
|
286
|
+
end
|
287
|
+
attr_reader :out, :err
|
288
|
+
def name
|
289
|
+
interface.namespace_name
|
290
|
+
end
|
291
|
+
alias_method :inspect, :name
|
292
|
+
def self.build name, &block
|
293
|
+
name = name.to_s
|
294
|
+
Class.new(self).class_eval do
|
295
|
+
self.namespace_name = name
|
296
|
+
x = class << self; self end
|
297
|
+
x.send(:define_method, :inspect) { "#<#{name}:Namespace>" }
|
298
|
+
x.send(:alias_method, :to_s, :inspect)
|
299
|
+
class_eval(&block)
|
300
|
+
self
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
class << self
|
305
|
+
def for_run parent, name_as_used
|
306
|
+
namespace_runner = new
|
307
|
+
namespace_runner.init_for_run parent, name_as_used
|
308
|
+
namespace_runner
|
309
|
+
end
|
310
|
+
def method_symbol
|
311
|
+
nil # for compat with etc
|
312
|
+
end
|
313
|
+
def name
|
314
|
+
@namespace_name
|
315
|
+
end
|
316
|
+
def namespace_name= ns_name
|
317
|
+
@namespace_name = ns_name.to_s
|
318
|
+
end
|
319
|
+
attr_reader :namespace_name
|
320
|
+
def parent= parent
|
321
|
+
@parent and fail("won't overwrite parent")
|
322
|
+
@parent = parent
|
323
|
+
end
|
324
|
+
def summary
|
325
|
+
a = command_tree.map { |c| hi(c.name) }
|
326
|
+
["child command#{'s' if a.length != 1}: {#{a * '|'}}"]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
class Tmx::Face::Cli
|
334
|
+
extend Tmx::Face::Command::TreeDefiner
|
335
|
+
include Tmx::Face::Colors
|
336
|
+
include Tmx::Face::Command::Nodeish
|
337
|
+
include Tmx::Face::Command::Treeish
|
338
|
+
|
339
|
+
def initialize
|
340
|
+
@out = $stdout
|
341
|
+
@err = $stderr
|
342
|
+
end
|
343
|
+
attr_reader :out, :err
|
344
|
+
alias_method :interface, :class
|
345
|
+
def argument_error e, cmd
|
346
|
+
e.backtrace[0,2].detect { |s| s.match(/\A[^:]+/)[0] == __FILE__ } or raise e
|
347
|
+
msg = e.message.sub(/\((\d+) for (\d+)\)\Z/) do
|
348
|
+
"(#{$1.to_i - 1} for #{$2.to_i - 1})"
|
349
|
+
end
|
350
|
+
cmd.usage msg
|
351
|
+
end
|
352
|
+
def program_name
|
353
|
+
@program_name ||= File.basename($PROGRAM_NAME)
|
354
|
+
end
|
355
|
+
alias_method :invocation_string, :program_name
|
356
|
+
def run argv
|
357
|
+
argv.empty? and return empty_argv
|
358
|
+
runner = self
|
359
|
+
begin
|
360
|
+
argv.first =~ /^-/ and return runner.run_opts(argv)
|
361
|
+
cmd = runner.find_command(argv)
|
362
|
+
end while (cmd and cmd.respond_to?(:find_command) and runner = cmd)
|
363
|
+
cmd and req = cmd.parse(argv) and
|
364
|
+
begin
|
365
|
+
req.command = cmd
|
366
|
+
runner.send(cmd.method_symbol, req, * req.method_parameters)
|
367
|
+
rescue ArgumentError => e
|
368
|
+
argument_error e, cmd
|
369
|
+
end
|
370
|
+
end
|
371
|
+
def version
|
372
|
+
@err.puts hi([program_name, interface.version].compact.join(' '))
|
373
|
+
end
|
374
|
+
class << self
|
375
|
+
def version *a, &block
|
376
|
+
if a.any? and block
|
377
|
+
raise ArgumentError.new("can't process args and block together.")
|
378
|
+
elsif a.any? or block
|
379
|
+
option_definitions.detect { |arr, _| '-v' == arr[0] } or
|
380
|
+
on('-v', '--version', 'shows version') { version }
|
381
|
+
if block
|
382
|
+
@version = block
|
383
|
+
else
|
384
|
+
@version = a.length == 1 ? a.first : a
|
385
|
+
end
|
386
|
+
else
|
387
|
+
@version.kind_of?(Proc) ? @version.call : @version
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
data/lib-iterm.sh
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
## NOTE for `iterm` users -- this file is not used: it is here for reference.
|
4
|
+
## (it lives in a different git repository)
|
5
|
+
|
6
|
+
# adapted from http://kpumuk.info/mac-os-x/how-to-show-ssh-host-name-on-the-iterms-background/
|
7
|
+
|
8
|
+
HEIGHT_TALL=750
|
9
|
+
WIDTH_NARROW=600
|
10
|
+
WIDTH_SCROLLBAR=15
|
11
|
+
HEIGHT_TITLEBAR_TABS=44
|
12
|
+
|
13
|
+
# arr=($(iterm_bounds_get))
|
14
|
+
function iterm_bounds_get {
|
15
|
+
local size=( $(
|
16
|
+
osascript -e "
|
17
|
+
tell application \"iTerm\"
|
18
|
+
get the bounds of the first window
|
19
|
+
end tell" | tr ',' ' '
|
20
|
+
) )
|
21
|
+
echo "${size[@]}"
|
22
|
+
}
|
23
|
+
|
24
|
+
function iterm_bounds_set {
|
25
|
+
if [[ ! "$1,$2,$3,$4" =~ "^[0-9]+,[0-9]+,[0-9]+,[0-9]+$" ]] ; then
|
26
|
+
echo "bad args to item_bounds_set: ($1, $2, $3, $4)"
|
27
|
+
return
|
28
|
+
fi
|
29
|
+
local exec_me="
|
30
|
+
tell application \"iTerm\"
|
31
|
+
set the bounds of the first window to {$1, $2, $3, $4}
|
32
|
+
end tell
|
33
|
+
"
|
34
|
+
osascript -e "$exec_me"
|
35
|
+
}
|
36
|
+
|
37
|
+
function iterm_dimensions_get {
|
38
|
+
local size=($(iterm_bounds_get))
|
39
|
+
local x1=${size[0]} y1=${size[1]} x2=${size[2]} y2=${size[3]}
|
40
|
+
local w=$(( $x2 - $x1 - $WIDTH_SCROLLBAR))
|
41
|
+
local h=$(( $y2 - $y1 - $HEIGHT_TITLEBAR_TABS))
|
42
|
+
echo "${w}x${h}"
|
43
|
+
}
|
44
|
+
|
45
|
+
function iterm_dimensions_set {
|
46
|
+
local w=$1 h=$2
|
47
|
+
local b=($(iterm_bounds_get))
|
48
|
+
local x=${b[0]} y=${b[1]}
|
49
|
+
iterm_bounds_set $x $y $w $h
|
50
|
+
}
|
51
|
+
|
52
|
+
# check to see if we have the correct terminal for doing this kind of thing
|
53
|
+
# this won't work when we sudo something because TERM_PROGRAM isn't picked up
|
54
|
+
function iterm_ok {
|
55
|
+
if [ "$(tty)" == 'not a tty' ] || [ "$TERM_PROGRAM" != "iTerm.app" ] ; then
|
56
|
+
echo ''
|
57
|
+
else
|
58
|
+
echo 'ok'
|
59
|
+
fi
|
60
|
+
}
|
61
|
+
|
62
|
+
function iterm_set {
|
63
|
+
local prop=$1
|
64
|
+
local val=$2
|
65
|
+
local tty=$(tty)
|
66
|
+
osascript -e "
|
67
|
+
tell application \"iTerm\"
|
68
|
+
repeat with theTerminal in terminals
|
69
|
+
tell theTerminal
|
70
|
+
try
|
71
|
+
tell session id \"$tty\"
|
72
|
+
set bounds of window 1 to \"$val\"
|
73
|
+
end tell
|
74
|
+
on error errmesg number errn
|
75
|
+
end try
|
76
|
+
end tell
|
77
|
+
end repeat
|
78
|
+
end tell
|
79
|
+
"
|
80
|
+
}
|
81
|
+
|
82
|
+
function iterm_bg_image_make {
|
83
|
+
local text1=$1
|
84
|
+
local text2=$2
|
85
|
+
local color_bg=${3:-#000000}
|
86
|
+
local color_fg=${4:-#662020}
|
87
|
+
local dimensions=$(iterm_dimensions_get)
|
88
|
+
local font_ttf=${5:-$HOME/.bash/resources/SimpleLife.ttf}
|
89
|
+
local font_points=${6:-60}
|
90
|
+
local font_style=${7:-Normal} # Font style (Any, Italic, Normal, Oblique)
|
91
|
+
local gravity=${8:-NorthEast}
|
92
|
+
# Text gravity (NorthWest, North, NorthEast,
|
93
|
+
# West, Center, East, SouthWest, South, SouthEast)
|
94
|
+
local offset1=${8:-20,10}
|
95
|
+
local offset2=${9:-20,80}
|
96
|
+
local outpath="/tmp/iTermBG.$$.png"
|
97
|
+
convert \
|
98
|
+
-size "$dimensions" xc:"$color_bg" -gravity "$gravity" -fill "$color_fg" \
|
99
|
+
-font "$font_ttf" -style "$font_style" -pointsize "$font_points" \
|
100
|
+
-antialias -draw "text $offset1 '$text1'" \
|
101
|
+
-pointsize 30 -draw "text $offset2 '$text2'" \
|
102
|
+
"$outpath"
|
103
|
+
echo $outpath
|
104
|
+
}
|
105
|
+
|
106
|
+
function iterm_bg_image_delete {
|
107
|
+
local path=${1:-/tmp/itermBG.$$.png}
|
108
|
+
rm $path
|
109
|
+
}
|
110
|
+
|
111
|
+
function iterm_bg_image_empty {
|
112
|
+
local opath="/tmp/iTermBG.empty.png"
|
113
|
+
if [ ! -f /tmp/iTermBG.empty.png ]; then
|
114
|
+
local dims=$(iterm_dimensions_get)
|
115
|
+
convert -size "$dims" xc:"#000000" "$opath"
|
116
|
+
fi
|
117
|
+
echo $opath
|
118
|
+
}
|
119
|
+
|
120
|
+
function iterm_bg_image_set {
|
121
|
+
local tty=$(tty)
|
122
|
+
osascript -e "
|
123
|
+
tell application \"iTerm\"
|
124
|
+
repeat with theTerminal in terminals
|
125
|
+
tell theTerminal
|
126
|
+
try
|
127
|
+
tell session id \"$tty\"
|
128
|
+
set background image path to \"$1\"
|
129
|
+
end tell
|
130
|
+
on error errmesg number errn
|
131
|
+
end try
|
132
|
+
end tell
|
133
|
+
end repeat
|
134
|
+
end tell
|
135
|
+
"
|
136
|
+
}
|
137
|
+
|
138
|
+
function iterm_bg_color_set {
|
139
|
+
local tty=$(tty)
|
140
|
+
osascript -e "
|
141
|
+
tell application \"iTerm\"
|
142
|
+
repeat with theTerminal in terminals
|
143
|
+
tell theTerminal
|
144
|
+
try
|
145
|
+
tell session id \"$tty\"
|
146
|
+
set background image path to \"\"
|
147
|
+
set background color to \"$1\"
|
148
|
+
end tell
|
149
|
+
on error errmesg number errn
|
150
|
+
end try
|
151
|
+
end tell
|
152
|
+
end repeat
|
153
|
+
end tell
|
154
|
+
"
|
155
|
+
}
|
156
|
+
|
157
|
+
function iterm_window_title_set {
|
158
|
+
osascript -e "
|
159
|
+
tell application \"iTerm\"
|
160
|
+
set the name of the first window to \"$1\"
|
161
|
+
end tell
|
162
|
+
"
|
163
|
+
}
|
data/myterm.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "myterm/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "myterm"
|
7
|
+
s.version = Skylab::Myterm::VERSION
|
8
|
+
s.authors = ["Mark Meves"]
|
9
|
+
s.email = ["mark.meves@gmail.com"]
|
10
|
+
s.homepage = "http://botnoise.org"
|
11
|
+
s.summary = %q{Command line interface for customizing iTerm using AppleScript}
|
12
|
+
s.description = %q{Command line interface for customizing iTerm using AppleScript.
|
13
|
+
Creates meaningful, salient, eye-catching background images that help to discern between iTerm windows.}.gsub(/\n */, ' ')
|
14
|
+
|
15
|
+
s.rubyforge_project = "myterm"
|
16
|
+
|
17
|
+
s.add_dependency 'rb-appscript'
|
18
|
+
s.add_dependency 'highline'
|
19
|
+
s.add_development_dependency "ruby-debug19"
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
# s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: myterm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mark Meves
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-06 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rb-appscript
|
17
|
+
requirement: &70161455195900 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70161455195900
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: highline
|
28
|
+
requirement: &70161455195480 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70161455195480
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: ruby-debug19
|
39
|
+
requirement: &70161455195060 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70161455195060
|
48
|
+
description: Command line interface for customizing iTerm using AppleScript. Creates
|
49
|
+
meaningful, salient, eye-catching background images that help to discern between
|
50
|
+
iTerm windows.
|
51
|
+
email:
|
52
|
+
- mark.meves@gmail.com
|
53
|
+
executables:
|
54
|
+
- myterm
|
55
|
+
extensions: []
|
56
|
+
extra_rdoc_files: []
|
57
|
+
files:
|
58
|
+
- ._repath.rb
|
59
|
+
- .gitignore
|
60
|
+
- .repath.sh
|
61
|
+
- .rvmrc.example
|
62
|
+
- Gemfile
|
63
|
+
- Gemfile.lock
|
64
|
+
- README.md
|
65
|
+
- bin/myterm
|
66
|
+
- doc/HISTORY.md
|
67
|
+
- lib-iterm.sh
|
68
|
+
- lib/myterm/api.rb
|
69
|
+
- lib/myterm/cli.rb
|
70
|
+
- lib/myterm/vendor/face/cli.rb
|
71
|
+
- lib/myterm/version.rb
|
72
|
+
- myterm.gemspec
|
73
|
+
has_rdoc: true
|
74
|
+
homepage: http://botnoise.org
|
75
|
+
licenses: []
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project: myterm
|
94
|
+
rubygems_version: 1.6.2
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: Command line interface for customizing iTerm using AppleScript
|
98
|
+
test_files: []
|