rmate 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.mdown +20 -0
  2. data/bin/rmate +195 -0
  3. metadata +71 -0
@@ -0,0 +1,20 @@
1
+ # rmate
2
+
3
+ If you wish to activate TextMate from an ssh session you can do so by copying the `rmate` (ruby) script to the server you are logged into. The script will connect back to TextMate running on your Mac so you should setup an ssh tunnel (as your Mac is likely behind NAT):
4
+
5
+ ssh -R 52698:127.0.0.1:52698 «server»
6
+
7
+ # Usage
8
+
9
+ Call `rmate --help` for options. Default options can be set in `/etc/rmate.rc` or `~/.rmate.rc`, e.g.:
10
+
11
+ host: auto
12
+ port: 52698
13
+
14
+ You can also set the `RMATE_HOST` and `RMATE_PORT` environment variables.
15
+
16
+ For more info see this [blog post about rmate](http://blog.macromates.com/2011/mate-and-rmate/ "TextMate Blog » mate and rmate").
17
+
18
+ # Ports
19
+
20
+ - [Bash](https://github.com/aurora/rmate) by Harald Lapp
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ $VERBOSE = true # -w
5
+ $KCODE = "U" if RUBY_VERSION < "1.9" # -KU
6
+
7
+ require 'optparse'
8
+ require 'socket'
9
+ require 'tempfile'
10
+ require 'yaml'
11
+
12
+ VERSION_STRING = 'rmate version 1.5 (2012-09-19)'
13
+
14
+ class Settings
15
+ attr_accessor :host, :port, :wait, :force, :verbose, :lines, :names, :types
16
+
17
+ def initialize
18
+ @host, @port = 'localhost', 52698
19
+
20
+ @wait = false
21
+ @force = false
22
+ @verbose = false
23
+ @lines = []
24
+ @names = []
25
+ @types = []
26
+
27
+ read_disk_settings
28
+
29
+ @host = ENV['RMATE_HOST'].to_s if ENV.has_key? 'RMATE_HOST'
30
+ @port = ENV['RMATE_PORT'].to_i if ENV.has_key? 'RMATE_PORT'
31
+
32
+ parse_cli_options
33
+
34
+ @host = parse_ssh_connection if @host == 'auto'
35
+ end
36
+
37
+ def read_disk_settings
38
+ [ "/etc/rmate.rc", "~/.rmate.rc"].each do |current_file|
39
+ file = File.expand_path current_file
40
+ if File.exist? file
41
+ params = YAML::load(File.open(file))
42
+ @host = params["host"] unless params["host"].nil?
43
+ @port = params["port"] unless params["port"].nil?
44
+ end
45
+ end
46
+ end
47
+
48
+ def parse_cli_options
49
+ OptionParser.new do |o|
50
+ o.on( '--host=name', "Connect to host.", "Use 'auto' to detect the host from SSH.", "Defaults to #{@host}.") { |v| @host = v }
51
+ o.on('-p', '--port=#', Integer, "Port number to use for connection.", "Defaults to #{@port}.") { |v| @port = v }
52
+ o.on('-w', '--[no-]wait', 'Wait for file to be closed by TextMate.') { |v| @wait = v }
53
+ o.on('-l', '--line [NUMBER]', 'Place caret on line [NUMBER] after loading file.') { |v| @lines <<= v }
54
+ o.on('-m', '--name [NAME]', 'The display name shown in TextMate.') { |v| @names <<= v }
55
+ o.on('-t', '--type [TYPE]', 'Treat file as having [TYPE].') { |v| @types <<= v }
56
+ o.on('-f', '--force', 'Open even if the file is not writable.') { |v| @force = v }
57
+ o.on('-v', '--verbose', 'Verbose logging messages.') { |v| @verbose = v }
58
+ o.on_tail('-h', '--help', 'Show this message.') { puts o; exit }
59
+ o.on_tail( '--version', 'Show version.') { puts VERSION_STRING; exit }
60
+ o.parse!
61
+ end
62
+ end
63
+
64
+ def parse_ssh_connection
65
+ ENV['SSH_CONNECTION'].nil? ? 'localhost' : ENV['SSH_CONNECTION'].split(' ').first
66
+ end
67
+ end
68
+
69
+ class Command
70
+ def initialize(name)
71
+ @command = name
72
+ @variables = {}
73
+ @data = nil
74
+ @size = nil
75
+ end
76
+
77
+ def []=(name, value)
78
+ @variables[name] = value
79
+ end
80
+
81
+ def read_file(path)
82
+ @size = File.size(path)
83
+ @data = File.open(path, "rb") { |io| io.read(@size) }
84
+ end
85
+
86
+ def send(socket)
87
+ socket.puts @command
88
+ @variables.each_pair do |name, value|
89
+ value = 'yes' if value === true
90
+ socket.puts "#{name}: #{value}"
91
+ end
92
+ if @data
93
+ socket.puts "data: #{@size}"
94
+ socket.puts @data
95
+ end
96
+ socket.puts
97
+ end
98
+ end
99
+
100
+ def handle_save(socket, variables, data)
101
+ path = variables["token"]
102
+ $stderr.puts "Saving #{path}" if $settings.verbose
103
+ begin
104
+ backup_path = "#{path}~"
105
+ backup_path = "#{backup_path}~" while File.exists? backup_path
106
+ File.link(path, backup_path) if File.exist? path
107
+ Tempfile.open("rmate", File.dirname(path)) do |temp|
108
+ temp.close(false)
109
+ if File.exists?(path)
110
+ if stat = File.stat(path)
111
+ File.chown(stat.uid, stat.gid, temp.path)
112
+ File.chmod(stat.mode, temp.path)
113
+ end
114
+ end
115
+ open(temp.path, 'wb') {|file| file << data }
116
+ File.rename(temp.path, path)
117
+ end
118
+ File.unlink(backup_path) if File.exist? backup_path
119
+ rescue
120
+ # TODO We probably want some way to notify the server app that the save failed
121
+ $stderr.puts "Save failed! #{$!}" if $settings.verbose
122
+ end
123
+ end
124
+
125
+ def handle_close(socket, variables, data)
126
+ path = variables["token"]
127
+ $stderr.puts "Closed #{path}" if $settings.verbose
128
+ end
129
+
130
+ def handle_cmd(socket)
131
+ cmd = socket.readline.chomp
132
+
133
+ variables = {}
134
+ data = ""
135
+
136
+ while line = socket.readline.chomp
137
+ break if line.empty?
138
+ name, value = line.split(': ', 2)
139
+ variables[name] = value
140
+ data << socket.read(value.to_i) if name == "data"
141
+ end
142
+ variables.delete("data")
143
+
144
+ case cmd
145
+ when "save" then handle_save(socket, variables, data)
146
+ when "close" then handle_close(socket, variables, data)
147
+ else abort "Received unknown command “#{cmd}”, exiting."
148
+ end
149
+ end
150
+
151
+ def connect_and_handle_cmds(host, port, cmds)
152
+ socket = TCPSocket.new(host, port)
153
+ server_info = socket.readline.chomp
154
+ $stderr.puts "Connect: ‘#{server_info}’" if $settings.verbose
155
+
156
+ cmds.each { |cmd| cmd.send(socket) }
157
+
158
+ socket.puts "."
159
+ handle_cmd(socket) while !socket.eof?
160
+ socket.close
161
+ $stderr.puts "Done" if $settings.verbose
162
+ end
163
+
164
+ ## MAIN
165
+
166
+ $settings = Settings.new
167
+
168
+ ## Parse arguments.
169
+ cmds = []
170
+ ARGV.each_index do |idx|
171
+ path = ARGV[idx]
172
+ abort "File #{path} is not writable! Use -f/--force to open anyway." unless $settings.force or File.writable? path or not File.exists? path
173
+ $stderr.puts "File #{path} is not writable. Opening anyway." if not File.writable? path and File.exists? path and $settings.verbose
174
+ cmd = Command.new("open")
175
+ cmd['display-name'] = "#{Socket.gethostname}:#{path}"
176
+ cmd['display-name'] = $settings.names[idx] if $settings.names.length > idx
177
+ cmd['real-path'] = File.expand_path(path)
178
+ cmd['data-on-save'] = true
179
+ cmd['re-activate'] = true
180
+ cmd['token'] = path
181
+ cmd['selection'] = $settings.lines[idx] if $settings.lines.length > idx
182
+ cmd['file-type'] = $settings.types[idx] if $settings.types.length > idx
183
+ cmd.read_file(path) if File.exist? path
184
+ cmd['data'] = "0" unless File.exist? path
185
+ cmds << cmd
186
+ end
187
+
188
+ unless $settings.wait
189
+ pid = fork do
190
+ connect_and_handle_cmds($settings.host, $settings.port, cmds)
191
+ end
192
+ Process.detach(pid)
193
+ else
194
+ connect_and_handle_cmds($settings.host, $settings.port, cmds)
195
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rmate
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 5
8
+ - 1
9
+ version: 1.5.1
10
+ platform: ruby
11
+ authors:
12
+ - Alex Ross
13
+ - Allan Odgaard
14
+ - "Ciar\xC3\xA1n Walsh"
15
+ - James Edward Gray II
16
+ - John St. John
17
+ - Nicolas Ledez
18
+ - OZAWA Sakuro
19
+ - Timothy Andrew
20
+ - Toby Butzon
21
+ autorequire:
22
+ bindir: bin
23
+ cert_chain: []
24
+
25
+ date: 2013-03-16 00:00:00 +01:00
26
+ default_executable:
27
+ dependencies: []
28
+
29
+ description: This program can be used to edit text files in TextMate 2 running on your local Mac.
30
+ email: rmate@textmate.org
31
+ executables: []
32
+
33
+ extensions: []
34
+
35
+ extra_rdoc_files: []
36
+
37
+ files:
38
+ - bin/rmate
39
+ - README.mdown
40
+ has_rdoc: true
41
+ homepage: https://github.com/textmate/rmate
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.6
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Proxy edits to a Mac running TextMate 2
70
+ test_files: []
71
+