myterm 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|