tmux-ruby 0.0.2

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.
Files changed (40) hide show
  1. data/.yardopts +1 -0
  2. data/LICENSE +22 -0
  3. data/README.md +23 -0
  4. data/lib/tmux.rb +56 -0
  5. data/lib/tmux/buffer.rb +131 -0
  6. data/lib/tmux/client.rb +193 -0
  7. data/lib/tmux/exception.rb +5 -0
  8. data/lib/tmux/exception/basic_exception.rb +6 -0
  9. data/lib/tmux/exception/in_tmux.rb +9 -0
  10. data/lib/tmux/exception/index_in_use.rb +9 -0
  11. data/lib/tmux/exception/unknown_command.rb +9 -0
  12. data/lib/tmux/exception/unsupported_version.rb +15 -0
  13. data/lib/tmux/filterable_hash.rb +15 -0
  14. data/lib/tmux/options.rb +109 -0
  15. data/lib/tmux/options/attr_option.rb +10 -0
  16. data/lib/tmux/options/bell_action_option.rb +19 -0
  17. data/lib/tmux/options/boolean_option.rb +26 -0
  18. data/lib/tmux/options/char_array_option.rb +26 -0
  19. data/lib/tmux/options/clock_mode_style_option.rb +27 -0
  20. data/lib/tmux/options/color_option.rb +23 -0
  21. data/lib/tmux/options/justification_option.rb +19 -0
  22. data/lib/tmux/options/keymap_option.rb +19 -0
  23. data/lib/tmux/options/number_option.rb +26 -0
  24. data/lib/tmux/options/option.rb +38 -0
  25. data/lib/tmux/options/string_option.rb +26 -0
  26. data/lib/tmux/options/symbol_option.rb +26 -0
  27. data/lib/tmux/options/word_array_option.rb +26 -0
  28. data/lib/tmux/options_list.rb +150 -0
  29. data/lib/tmux/pane.rb +496 -0
  30. data/lib/tmux/server.rb +217 -0
  31. data/lib/tmux/session.rb +312 -0
  32. data/lib/tmux/status_bar.rb +134 -0
  33. data/lib/tmux/status_bar/field.rb +129 -0
  34. data/lib/tmux/version.rb +4 -0
  35. data/lib/tmux/widget.rb +35 -0
  36. data/lib/tmux/widgets/progress_bar.rb +107 -0
  37. data/lib/tmux/window.rb +697 -0
  38. data/lib/tmux/window/status.rb +21 -0
  39. data/lib/tmux/window/status/state.rb +87 -0
  40. metadata +96 -0
@@ -0,0 +1,217 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Tmux
3
+ class Server
4
+ include Comparable
5
+
6
+ # Creates a new session
7
+ #
8
+ # @option args [Boolean] :attach (false) Attach to the new session?
9
+ # @option args [String] :name (nil) Name of the new session. Will
10
+ # be automatically generated of nil.
11
+ # @option args [String] :window_name (nil) Name of the initial
12
+ # window. Cannot be used when grouping sessions.
13
+ # @option args [Session] :group_with (nil) Group with this
14
+ # session, sharing all windows.
15
+ # @option args [String] :command (nil) Execute this command in the
16
+ # initial window. Cannot be used when grouping sessions.
17
+ #
18
+ # @return [Session, nil] Returns the new {Session session} if a
19
+ # `:name` has been given and if `:attach` is false
20
+ #
21
+ # @raise [ArgumentError] if combining `:group_with` and `:window_name`
22
+ # or :command
23
+ #
24
+ # @tmuxver >=1.4
25
+ def create_session(args = {})
26
+ check_for_version!("1.4")
27
+
28
+ if args[:group_with] && (args[:window_name] || args[:command])
29
+ raise ArgumentError, "Cannot combine :group_with and :window_name or :command"
30
+ end
31
+
32
+ # FIXME shell escape names
33
+ flags = []
34
+ flags << "-d" unless args[:attach]
35
+ flags << "-n '#{args[:window_name]}'" if args[:window_name]
36
+ flags << "-s '#{args[:name]}'" if args[:name]
37
+ flags << "-t '#{args[:group_with].name}'" if args[:group_with]
38
+ flags << args[:command] if args[:command]
39
+
40
+ command = "new-session #{flags.join(" ")}"
41
+
42
+ ret = invoke_command(command, true)
43
+ if ret.start_with?("duplicate session:")
44
+ raise RuntimeError, ret
45
+ elsif ret.start_with?("sessions should be nested with care.")
46
+ raise Exception::InTmux("new-session")
47
+ else
48
+ if args[:name] and !args[:attach]
49
+ return Session.new(self, args[:name])
50
+ end
51
+ end
52
+ end
53
+
54
+ # @return [String]
55
+ attr_reader :socket
56
+ # @return [OptionsList]
57
+ attr_reader :options
58
+ # @param [String] socket A socket *name*.
59
+ def initialize(socket = "default")
60
+ @socket = socket
61
+ @options = OptionsList.new(:server, self, false)
62
+ end
63
+
64
+ # @return [-1, 0, 1]
65
+ def <=>(other)
66
+ return nil unless other.is_a?(Server)
67
+ @socket <=> other.socket
68
+ end
69
+
70
+ # @return [Server] Returns self. This is useful for other classes
71
+ # which can operate on Server, {Session}, {Window}, {Pane} and so
72
+ # on
73
+ attr_reader :server
74
+ undef_method "server"
75
+ def server
76
+ self
77
+ end
78
+
79
+ # Invokes a tmux command.
80
+ #
81
+ # @param [String] command The command to invoke
82
+ # @return [void]
83
+ def invoke_command(command, unset_tmux = false)
84
+ Tmux.invoke_command("-L #@socket #{command}", unset_tmux)
85
+ end
86
+
87
+ # Kills a server and thus all {Session sessions}, {Window windows} and {Client clients}.
88
+ #
89
+ # @tmux kill-server
90
+ # @return [void]
91
+ def kill
92
+ invoke_command "kill-server"
93
+ end
94
+
95
+ # Sources a file, that is load and evaluate it in tmux.
96
+ #
97
+ # @param [String] file Name of the file to source
98
+ # @tmux source-file
99
+ # @return [void]
100
+ def source_file(file)
101
+ invoke_command "source-file #{file}"
102
+ end
103
+ alias_method :load, :source_file
104
+
105
+ # @tmux list-sessions
106
+ # @param [Hash] search Filters the resulting hash using {FilterableHash#filter}
107
+ # @return [Hash] A hash with information for all sessions
108
+ def sessions_information(search = {})
109
+ hash = {}
110
+ output = invoke_command "list-sessions"
111
+ output.each_line do |session|
112
+ params = session.match(/^(?<name>\w+?): (?<num_windows>\d+) windows \(created (?<creation_time>.+?)\) \[(?<width>\d+)x(?<height>\d+)\](?: \((?<attached>attached)\))?$/)
113
+
114
+ name = params[:name]
115
+ num_windows = params[:num_windows].to_i
116
+ creation_time = Date.parse(params[:creation_time])
117
+ width = params[:width].to_i
118
+ height = params[:height].to_i
119
+ attached = !!params[:attached]
120
+
121
+ hash[name] = {
122
+ :name => name,
123
+ :num_windows => num_windows,
124
+ :creation_time => creation_time,
125
+ :width => width,
126
+ :height => height,
127
+ :attached => attached,
128
+ }
129
+ end
130
+ hash.extend FilterableHash
131
+ hash.filter(search)
132
+ end
133
+
134
+ # @tmux list-sessions
135
+ # @return [Array<Session>] All {Session sessions}
136
+ attr_reader :sessions
137
+ undef_method "sessions"
138
+ def sessions(search = {})
139
+ sessions_information(search).map do |name, information|
140
+ Session.new(self, name)
141
+ end
142
+ end
143
+
144
+ # @return [Session] The first {Session session}. This is
145
+ # especially useful if working with a server that only has one
146
+ # {Session session}.
147
+ attr_reader :session
148
+ undef_method "session"
149
+ def session
150
+ sessions.first
151
+ end
152
+
153
+ # @tmux list-clients
154
+ # @param [Hash] search Filters the resulting hash using {FilterableHash#filter}
155
+ # @return [Hash] A hash with information for all clients
156
+ def clients_information(search = {})
157
+ clients = invoke_command "list-clients"
158
+ hash = {}
159
+ clients.each_line do |client|
160
+ params = client.match(/^(?<device>.+?): (?<session>\d+) \[(?<width>\d+)x(?<height>\d+) (?<term>.+?)\](?: \((?<utf8>utf8)\))?$/)
161
+ device = params[:device]
162
+ session = sessions[params[:session].to_i]
163
+ width = params[:width].to_i
164
+ height = params[:height].to_i
165
+ term = params[:term]
166
+ utf8 = !!params[:utf8]
167
+
168
+ hash[device] = {
169
+ :device => device,
170
+ :session => session,
171
+ :width => width,
172
+ :height => height,
173
+ :term => term,
174
+ :utf8 => utf8,
175
+ }
176
+ end
177
+ hash.extend FilterableHash
178
+ hash.filter(search)
179
+ end
180
+
181
+ # @tmux list-clients
182
+ # @return [Array<Client>]
183
+ attr_reader :clients
184
+ undef_method "clients"
185
+ def clients(search = {})
186
+ clients_information(search).map { |device, information|
187
+ Client.new(self, device)
188
+ }
189
+ end
190
+
191
+ # @tmux server-info
192
+ # @return [String] Information about the server
193
+ attr_reader :info
194
+ undef_method "info"
195
+ def info
196
+ invoke_command "server-info"
197
+ end
198
+
199
+ # @return [String] Version of the tmux server
200
+ attr_reader :version
201
+ undef_method "version"
202
+ def version
203
+ @version ||= info.lines.first.split(",").first[/([.\d]+)/]
204
+ end
205
+
206
+ # Checks if a version requirement is being met
207
+ #
208
+ # @param [String] required The version at least required
209
+ # @raise [Exception::UnsupportedVersion] Raised if a version requirement isn't met
210
+ # @return [void]
211
+ def check_for_version!(required)
212
+ if required > version
213
+ raise Exception::UnsupportedVersion, required
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,312 @@
1
+ module Tmux
2
+ # A session is a single collection of pseudo terminals under the
3
+ # management of {Tmux tmux}. Each session has one or more {Window
4
+ # windows} linked to it. A {Window window} occupies the entire
5
+ # screen and may be split into rectangular {Pane panes}, each of
6
+ # which is a separate pseudo terminal (the pty(4) manual page
7
+ # documents the technical details of pseudo terminals). Any number
8
+ # of tmux instances may connect to the same session, and any number
9
+ # of {Window windows} may be present in the same session. Once all
10
+ # sessions are {Session#kill killed}, tmux exits.
11
+ class Session
12
+ include Comparable
13
+
14
+ # @return [Options]
15
+ def self.options(session)
16
+ OptionsList.new(:session, session, true)
17
+ end
18
+
19
+ # Creates a new {Window window}.
20
+ #
21
+ # @option args [Boolean] :after_number (false) If true, the new
22
+ # {Window window} will be inserted at the next index up from the
23
+ # specified number (or the {Client#current_window current}
24
+ # {Window window}), moving {Window windows} up if necessary
25
+ # @option args [Boolean] :kill_existing (false) Kill an existing
26
+ # {Window window} if it conflicts with a desired number
27
+ # @option args [Boolean] :make_active (true) Switch to the newly
28
+ # generated {Window window}
29
+ # @option args [String] :name Name of the new {Window window}
30
+ # (optional)
31
+ # @option args [Number] :number Number of the new {Window window}
32
+ # (optional)
33
+ # @option args [String] :command Command to run in the new {Window
34
+ # window} (optional)
35
+ #
36
+ # @tmux new-window
37
+ # @return [Window] The newly created {Window window}
38
+ def create_window(args = {})
39
+ args = {
40
+ :kill_existing => false,
41
+ :make_active => true,
42
+ :after_number => false,
43
+ }.merge(args)
44
+
45
+ flags = []
46
+ # flags << "-d" unless args[:make_active]
47
+ flags << "-a" if args[:after_number]
48
+ flags << "-k" if args[:kill_existing]
49
+ flags << "-n '#{args[:name]}'" if args[:name] # FIXME escaping
50
+ flags << "-t #{args[:number]}" if args[:number]
51
+ flags << args[:command] if args[:command]
52
+
53
+ @server.invoke_command "new-window #{flags.join(" ")}"
54
+ new_window = current_window
55
+ unless args[:make_active]
56
+ select_last_window
57
+ end
58
+ # return Window.new(self, num)
59
+ return new_window
60
+ end
61
+
62
+ # @see Client#current_window
63
+ # @return (see Client#current_window)
64
+ attr_reader :current_window
65
+ undef_method "current_window"
66
+ def current_window
67
+ any_client.current_window
68
+ end
69
+
70
+ # @see Client#current_pane
71
+ # @return (see Client#current_pane)
72
+ attr_reader :current_pane
73
+ undef_method "current_pane"
74
+ def current_pane
75
+ any_client.current_pane
76
+ end
77
+
78
+ # Returns a {Client client} that is displaying the session.
79
+ #
80
+ # @return [Client, nil] A {Client client} that is displaying the session.
81
+ def any_client
82
+ @server.clients({:session => self}).first
83
+ end
84
+
85
+ # @return [Boolean]
86
+ def ==(other)
87
+ self.class == other.class && @server == other.server && @name == other.name
88
+ end
89
+
90
+ # @return [Number]
91
+ def hash
92
+ [@server.hash, @number].hash
93
+ end
94
+
95
+ # @return [Boolean]
96
+ def eql?(other)
97
+ self == other
98
+ end
99
+
100
+ def <=>(other)
101
+ return nil unless other.is_a?(Session)
102
+ [@server, @name] <=> [other.server, other.name]
103
+ end
104
+
105
+ # @overload name
106
+ # @return [String]
107
+ # @overload name=(new_name)
108
+ # Renames the session.
109
+ #
110
+ # @todo escape name
111
+ # @return [String]
112
+ # @tmux rename-session
113
+ # @return [String]
114
+ attr_accessor :name
115
+ undef_method "name="
116
+ # @return [Server]
117
+ attr_reader :server
118
+ # @return [OptionsList]
119
+ attr_reader :options
120
+ # @return [StatusBar]
121
+ attr_reader :status_bar
122
+ def initialize(server, name)
123
+ @server, @name = server, name
124
+ @status_bar = StatusBar.new(self)
125
+ @options = OptionsList.new(:session, self, false)
126
+ end
127
+
128
+ def name=(new_name)
129
+ raise ArgumentError if new_name.to_s.strip.empty?
130
+ ret = @server.invoke_command("rename-session -t #{identifier} '#{new_name}'")
131
+
132
+ if ret.start_with?("duplicate session:")
133
+ raise RuntimeError, ret
134
+ end
135
+
136
+ @name = new_name
137
+ end
138
+
139
+ # @return [String]
140
+ attr_reader :identifier
141
+ undef_method "identifier"
142
+ def identifier
143
+ @name
144
+ end
145
+
146
+ # Locks the session.
147
+ #
148
+ # @tmux lock-session
149
+ # @return [void]
150
+ # @tmuxver &gt;=1.1
151
+ def lock
152
+ @server.check_for_version!("1.1")
153
+
154
+ @server.invoke_command "lock-session -t #{identifier}"
155
+ end
156
+
157
+ # @return [Integer]
158
+ attr_reader :num_windows
159
+ undef_method "num_windows"
160
+ def num_windows
161
+ @server.sessions_information[@name][:num_windows]
162
+ end
163
+
164
+ # @return [Time]
165
+ attr_reader :creation_time
166
+ undef_method "creation_time"
167
+ def creation_time
168
+ @server.sessions_information[@name][:creation_time]
169
+ end
170
+ alias_method :created_at, :creation_time
171
+
172
+ # @return [Integer]
173
+ attr_reader :width
174
+ undef_method "width"
175
+ def width
176
+ @server.sessions_information[@name][:width]
177
+ end
178
+
179
+ # @return [Integer]
180
+ attr_reader :height
181
+ undef_method "height"
182
+ def height
183
+ @server.sessions_information[@name][:height]
184
+ end
185
+
186
+ # @return [Boolean]
187
+ attr_reader :attached
188
+ undef_method "attached"
189
+ def attached
190
+ @server.sessions_information[@name][:attached]
191
+ end
192
+ alias_method :attached?, :attached
193
+
194
+ # @return [Array<Client>] All {Client clients}
195
+ attr_reader :clients
196
+ undef_method "clients"
197
+ def clients
198
+ @server.clients({:session => self})
199
+ end
200
+
201
+ # Attach to a session. Replaces the ruby process.
202
+ #
203
+ # @return [void]
204
+ # @tmux attach
205
+ def attach
206
+ exec "#{Tmux::BINARY} attach -t #{identifier}"
207
+ end
208
+
209
+ # Kills the session.
210
+ #
211
+ # @tmux kill-session
212
+ # @return [void]
213
+ def kill
214
+ @server.invoke_command "kill-session -t #{identifier}"
215
+ end
216
+
217
+ # @tmux list-windows
218
+ # @tmuxver &gt;=1.1
219
+ # @param [Hash] search Filters the resulting hash using {FilterableHash#filter}
220
+ # @return [Hash] A hash with information for all windows
221
+ # @return [Hash]
222
+ def windows_information(search = {})
223
+ @server.check_for_version!("1.1")
224
+
225
+ hash = {}
226
+ output = @server.invoke_command "list-windows -t #{identifier}"
227
+ output.each_line do |session|
228
+ params = session.match(/^(?<num>\d+): (?<name>.+?) \[(?<width>\d+)x(?<height>\d+)\]$/)
229
+ next if params.nil? # >=1.3 displays layout information in indented lines
230
+ num = params[:num].to_i
231
+ name = params[:name]
232
+ width = params[:width].to_i
233
+ height = params[:height].to_i
234
+
235
+ hash[num] = {:num => num, :name => name, :width => width, :height => height}
236
+ end
237
+ hash.extend FilterableHash
238
+ hash.filter(search)
239
+ end
240
+
241
+ # @tmux list-windows
242
+ # @return [Hash{Number => Window}] All {Window windows}
243
+ # @tmuxver &gt;=1.1
244
+ attr_reader :windows
245
+ undef_method "windows"
246
+ def windows
247
+ hash = {}
248
+ @server.check_for_version!("1.1")
249
+
250
+ windows_information.each do |num, information|
251
+ hash[num] = Window.new(self, num)
252
+ end
253
+ hash
254
+ end
255
+
256
+ # @param [Hash] search Filters the resulting hash using {FilterableHash#filter}
257
+ # @return [Hash] A hash with information for all buffers
258
+ # @tmux list-buffers
259
+ def buffers_information(search = {})
260
+ hash = {}
261
+ buffers = @server.invoke_command "list-buffers -t #{identifier}"
262
+ buffers.each_line do |buffer|
263
+ num, size = buffer.match(/^(\d+): (\d+) bytes/)[1..2]
264
+ hash[num] = {:size => size}
265
+ end
266
+ hash.extend FilterableHash
267
+ hash.filter(search)
268
+ end
269
+
270
+ # @tmux list-buffers
271
+ # @return [Array<Buffer>] All {Buffer buffers}
272
+ attr_reader :buffers
273
+ undef_method "buffers"
274
+ def buffers
275
+ buffers_information.map do |num, information|
276
+ Buffer.new(num, self)
277
+ end
278
+ end
279
+
280
+ # @group Selecting
281
+
282
+ # Select the last (previously selected) window.
283
+ #
284
+ # @return [Window]
285
+ def select_last_window
286
+ @server.invoke_command "last-window -t #{identifier}"
287
+ current_window
288
+ end
289
+
290
+ # Selects the next (higher index) window
291
+ #
292
+ # @param [Number] num How many windows to move
293
+ # @tmuxver &gt;=1.3
294
+ # @return [Window]
295
+ def select_next_window(num = 1)
296
+ @server.invoke_command "select-window -t #{identifier}:+#{num}"
297
+ current_window
298
+ end
299
+
300
+ # Selects the previous (lower index) window
301
+ #
302
+ # @param [Number] num How many windows to move
303
+ # @tmuxver &gt;=1.3
304
+ # @return [Window]
305
+ def select_previous_window(num = 1)
306
+ @server.invoke_command "select-window -t:-#{num}"
307
+ current_window
308
+ end
309
+
310
+ # @endgroup
311
+ end
312
+ end