tmux-ruby 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,134 @@
1
+ require "tmux/status_bar/field"
2
+
3
+ module Tmux
4
+ # Every {Session session} has a status bar. This is where various
5
+ # information as well as a list of {Window windows} will be
6
+ # displayed. For this purpose, the status bar is divided into three
7
+ # parts: the left, center and right part. While the center part
8
+ # displays the window list, the left and right part can be set to
9
+ # display any text.
10
+ #
11
+ # This class allows accessing various attributes (e.g. the
12
+ # {#background_color background color} of the bar) and the
13
+ # editable parts ({#left left} and {#right right}).
14
+ #
15
+ # Note: You will not have to instantiate this class. Use
16
+ # {Session#status_bar} instead.
17
+ class StatusBar
18
+ # @return [Session]
19
+ attr_reader :session
20
+ # The left {Field field} which may display custom {Field#text
21
+ # text} and {Widget widgets}.
22
+ #
23
+ # @return [Field]
24
+ attr_reader :left
25
+
26
+ # The right {Field field} which may display custom {Field#text
27
+ # text} and {Widget widgets}.
28
+ #
29
+ # @return [Field]
30
+ attr_reader :right
31
+ # @param [Session] session
32
+ def initialize(session)
33
+ @session = session
34
+ @left = Field.new(self, :left)
35
+ @right = Field.new(self, :right)
36
+ end
37
+
38
+ # Hides the status bar.
39
+ #
40
+ # @return [void]
41
+ def hide
42
+ @session.options.status = false
43
+ end
44
+
45
+ # Shows the status bar.
46
+ #
47
+ # @return [void]
48
+ def show
49
+ @session.options.status = true
50
+ end
51
+
52
+ # @return [Symbol]
53
+ attr_accessor :background_color
54
+ undef_method "background_color"
55
+ undef_method "background_color="
56
+ def background_color
57
+ @session.options.status_bg
58
+ end
59
+
60
+ def background_color=(color)
61
+ @session.options.status_bg = color
62
+ end
63
+
64
+ # @return [Symbol]
65
+ attr_accessor :foreground_color
66
+ undef_method "foreground_color"
67
+ undef_method "foreground_color="
68
+ def foreground_color
69
+ @session.options.status_fg
70
+ end
71
+
72
+ def foreground_color=(color)
73
+ @session.options.status_fg = color
74
+ end
75
+
76
+ # @return [Number] The interval in which the status bar will be
77
+ # updated.
78
+ attr_accessor :interval
79
+ undef_method "interval"
80
+ undef_method "interval="
81
+ def interval
82
+ @session.options.status_interval
83
+ end
84
+
85
+ def interval=(value)
86
+ @session.options.status_interval = value
87
+ end
88
+
89
+ # Sets the justification of the window list component of the status
90
+ # line.
91
+ #
92
+ # @return [Symbol<:left, :right, :centre>]
93
+ attr_accessor :justification
94
+ undef_method "justification"
95
+ undef_method "justification="
96
+ def justification
97
+ @session.options.status_justify
98
+ end
99
+
100
+ def justification=(val)
101
+ @session.options.status_justify = val
102
+ end
103
+
104
+ # @return [Symbol<:emacs, :vi>]
105
+ attr_accessor :keymap
106
+ undef_method "keymap"
107
+ undef_method "keymap="
108
+ def keymap
109
+ # TODO keymap class?
110
+ @session.options.status_keys
111
+ end
112
+
113
+ def keymap=(val)
114
+ @session.options.status_keys = val
115
+ end
116
+
117
+ # Instruct tmux to treat top-bit-set characters in
118
+ # {StatusBar::Field#text} as UTF-8. Notably, this is important for
119
+ # wide characters. This option defaults to false.
120
+ #
121
+ # @return [Boolean]
122
+ attr_accessor :utf8
123
+ undef_method "utf8"
124
+ undef_method "utf8="
125
+ def utf8
126
+ @session.options.status_utf8
127
+ end
128
+ alias_method :utf8?, :utf8
129
+
130
+ def utf8=(bool)
131
+ @session.options.status_utf8 = bool
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,129 @@
1
+ module Tmux
2
+ class StatusBar
3
+ # This class represents a field in a {StatusBar status bar}. Every
4
+ # {StatusBar status bar} has two fields, one on the left side and
5
+ # one on the right side.
6
+ #
7
+ # A field can either display a simple {#text text}, or display a
8
+ # {Widget widget}. While only one {Widget widget} can be displayed
9
+ # at a time per field, a field will keep a stack of widgets, to
10
+ # and from which new {Widget widgets} can be {#push_widget pushed}
11
+ # and {#pop_widget popped}. This is useful for example when
12
+ # temporarily displaying a {Widgets::ProgressBar progress bar}.
13
+ class Field
14
+ def initialize(status_bar, side)
15
+ @status_bar = status_bar
16
+ @side = side
17
+ @widgets = []
18
+ @backups = []
19
+ end
20
+
21
+ # Pushes a widget to the stack, making it the currently visible
22
+ # one.
23
+ #
24
+ # @param [Widget] widget the widget to push to the stack
25
+ # @return [void]
26
+ def push_widget(widget)
27
+ @backups << self.text
28
+ @widgets << widget
29
+ widget.field = self
30
+ end
31
+ alias_method :add_widget, :push_widget
32
+
33
+ # Removes the current {Widget widget} from the stack.
34
+ #
35
+ # @param [Widget] pop If not nil, try to remove the specified
36
+ # widget instead of popping off the topmost one.
37
+ # @return [Widget, nil] the {Widget widget} which has been popped
38
+ def pop_widget(pop = nil)
39
+ widget = pop || @widgets.first
40
+ pos = @widgets.index(widget)
41
+ @widgets.delete_at(pos)
42
+ backup = @backups.delete_at(pos)
43
+
44
+ self.text = backup if backup and pos == 0
45
+ widget
46
+ end
47
+ alias_method :remove_widget, :pop_widget
48
+
49
+ # @overload widget
50
+ # @return [Widget] The currently displayed {Widget widget},
51
+ # that is the one on top of the stack.
52
+ # @overload widget=(widget)
53
+ # Overwrites the stack of {Widget widgets} and makes `widget` the only
54
+ # {Widget widget}.
55
+ #
56
+ # @return [Widget]
57
+ # @return [Widget] The currently displayed {Widget widget},
58
+ # that is the one on top of the stack.
59
+ attr_accessor :widget
60
+ undef_method "widget"
61
+ undef_method "widget="
62
+ def widget
63
+ @widgets.last
64
+ end
65
+
66
+ def widget=(widget)
67
+ restore
68
+ push_widget(widget)
69
+ end
70
+
71
+ # Removes all {Widget widgets} from the stack, restoring the
72
+ # {StatusBar status bar's} original state.
73
+ #
74
+ # @return [void]
75
+ def restore
76
+ while pop_widget; end
77
+ end
78
+
79
+ # @return [String]
80
+ attr_accessor :text
81
+ undef_method "text"
82
+ undef_method "text="
83
+ def text
84
+ @status_bar.session.options.get "status-#@side"
85
+ end
86
+
87
+ def text=(val)
88
+ meth = "status_#@side="
89
+ @status_bar.session.options.set "status-#@side", val
90
+ end
91
+
92
+ # @return [Symbol]
93
+ attr_accessor :background_color
94
+ undef_method "background_color"
95
+ undef_method "background_color="
96
+ def background_color
97
+ @status_bar.session.options.get "status-#@side-bg"
98
+ end
99
+
100
+ def background_color=(color)
101
+ @status_bar.session.options.set "status-#@side-bg", color
102
+ end
103
+
104
+ # @return [Symbol]
105
+ attr_accessor :foreground_color
106
+ undef_method "foreground_color"
107
+ undef_method "foreground_color="
108
+ def foreground_color
109
+ @status_bar.session.options.get "status-#@side-fg"
110
+ end
111
+
112
+ def foreground_color=(color)
113
+ @status_bar.session.options.set "status-#@side-fg", color
114
+ end
115
+
116
+ # @return [Number]
117
+ attr_accessor :max_length
118
+ undef_method "max_length"
119
+ undef_method "max_length="
120
+ def max_length
121
+ @status_bar.session.options.get "status-#@side-length"
122
+ end
123
+
124
+ def max_length=(num)
125
+ @status_bar.session.options.set "status-#@side-length", num
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,4 @@
1
+ module Tmux
2
+ # The version of this library
3
+ VERSION = "0.0.2".freeze
4
+ end
@@ -0,0 +1,35 @@
1
+ module Tmux
2
+ # @abstract Subclass this class, provide a meaningful #display
3
+ # method and make sure it is being called.
4
+ class Widget
5
+ # @return [Field]
6
+ attr_accessor :field
7
+ undef_method "field="
8
+
9
+ def field=(new_field)
10
+ @field = new_field
11
+ if new_field
12
+ @max_length = new_field.max_length # Cache this to avoid constantly pulling the option
13
+ else
14
+ @max_length = 0
15
+ end
16
+ end
17
+
18
+ def initialize
19
+ @max_length = 0
20
+ @field = nil
21
+ end
22
+
23
+ # Displays the widget if `@field` is not `nil`.
24
+ #
25
+ # @api abstract
26
+ # @return [void]
27
+ def display
28
+ end
29
+
30
+ # @return [Boolean] True if `@field` is not `nil` and `@max_length` is > 0
31
+ def can_display?
32
+ true if @field && @max_length > 0
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,107 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Tmux
3
+ module Widgets
4
+ # # Description
5
+ #
6
+ # Tmux::Widgets::ProgressBar offers an easy way of displaying progress
7
+ # bars in the {Tmux::StatusBar status bar}.
8
+ #
9
+ # Thanks to the widget and stack system of tmux-ruby, a progress
10
+ # bar can be temporarily displayed without destroying previous
11
+ # contents of the {Tmux::StatusBar status bar}, offering an
12
+ # unobtrusive way of displaying the progress of a long running
13
+ # system. As soon as the progress bar is not needed anymore, it
14
+ # can be removed from the stack, revealing any previous content of
15
+ # the {Tmux::StatusBar status bar}.
16
+ #
17
+ #
18
+ # # Features
19
+ #
20
+ # - a freely definable maximum value
21
+ # - automatic conversion of absolute values to their respective
22
+ # percentage
23
+ # - automatic scaling of the progress bar, adapting to the available width in the status bar
24
+ # - labels
25
+ #
26
+ #
27
+ # # Example
28
+ # require "tmux"
29
+ # require "tmux/widgets/progress_bar" # widgets won't be required by default
30
+ #
31
+ # server = Tmux::Server.new
32
+ # session = server.session # returns the first available session. Actual applications can determine the appropriate session.
33
+ #
34
+ # pbar = Tmux::Widgets::ProgressBar.new("Download") # initialize a new progress bar with the label "Download"
35
+ # session.status_bar.right.add_widget(pbar) # add the progress bar to the right part of the status bar and display it
36
+ #
37
+ # num_files = 24 # in a real application, we would dynamically determine the amount of files/mails/… to download
38
+ # pbar.total = num_files
39
+ #
40
+ # num_files.times do
41
+ # # in a real application, we would be downloading something here
42
+ # pbar.value += 1
43
+ # sleep 0.1
44
+ # end
45
+ #
46
+ # sleep 1 # give the user a chance to see that the process has finished
47
+ #
48
+ # # Remove the progress bar again, restoring any old content of the status bar.
49
+ # # Note: by passing the progress bar to #pop_widget, we avoid breaking the stack
50
+ # # if another application decided to display its own widget on top of ours.
51
+ # session.status_bar.right.pop_widget(pbar)
52
+ #
53
+ #
54
+ # # Screenshot
55
+ # ![Screenshot of ProgressBar](http://doc.fork-bomb.org/tmux/screenshots/progress_bar.png)
56
+
57
+ class ProgressBar < Widget
58
+ # @overload value
59
+ # @return [Number]
60
+ # @overload value=(new_value)
61
+ # Sets an absolute value. It will be automatically
62
+ # converted to a percentage when rendered.
63
+ #
64
+ # @return [Number]
65
+ # @return [Number]
66
+ attr_accessor :value
67
+ undef_method "value="
68
+
69
+ def value=(new_value)
70
+ @value = new_value
71
+ display
72
+ end
73
+
74
+ # @return [String]
75
+ attr_accessor :label
76
+ # @return [Number]
77
+ attr_accessor :total
78
+
79
+ # @param [String] label Label for the progress bar
80
+ # @param [Number] total The maximal value of the progress bar
81
+ # @param field (see Widget#initialize)
82
+ def initialize(label = "Progress", total = 100)
83
+ super()
84
+ @label = label
85
+ @total = total
86
+ @value = 0
87
+ end
88
+
89
+ # Display the progress bar. {#value=} automatically calls this
90
+ # method to update the widget.
91
+ #
92
+ # @return [void]
93
+ def display
94
+ return unless can_display?
95
+ s = "#{@label}: "
96
+ remaining_chars = @max_length - s.size - 3 # 3 = "|" + "|" + ">"
97
+ return if remaining_chars <= 0
98
+
99
+ bar = "=" * (((@value / @total.to_f) * remaining_chars).ceil - 1) + ">"
100
+ bar << " " * (remaining_chars - bar.size) unless (remaining_chars - bar.size) < 0
101
+ s << "|#{bar}|"
102
+
103
+ @field.text = s
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,697 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "tmux/window/status"
3
+
4
+ module Tmux
5
+ # A {Window window} occupies the entire
6
+ # screen and may be split into rectangular {Pane panes}, each of
7
+ # which is a separate pseudo terminal (the pty(4) manual page
8
+ # documents the technical details of pseudo terminals).
9
+ #
10
+ # @todo Figure out better names for some attributes, e.g. mode_mouse
11
+ class Window
12
+ include Comparable
13
+
14
+ class << self
15
+ # @return [OptionsList]
16
+ attr_reader :options
17
+ undef_method "options"
18
+ def options(server)
19
+ OptionsList.new(:window, server, true)
20
+ end
21
+ end
22
+
23
+ # @overload number
24
+ # @return [Number]
25
+ # @overload number=(new_number)
26
+ # @return [Number]
27
+ # @raise [Exception::IndexInUse]
28
+ # @see #move
29
+ # @return [Number]
30
+ attr_accessor :number
31
+ undef_method "number="
32
+
33
+ # @overload session
34
+ # @return [Session]
35
+ # @overload session=(new_session)
36
+ # Moves the window to another {Session session}. First it tries
37
+ # to reuse the current number of the window. If that number is
38
+ # already used in the new {Session session}, the first free
39
+ # number will be used instead.
40
+ #
41
+ # @return [Session]
42
+ # @raise [Exception::IndexInUse]
43
+ # @see #move
44
+ # @todo use base-index
45
+ # @return [Session]
46
+ attr_accessor :session
47
+ undef_method "session="
48
+ # @return [OptionsList]
49
+ attr_reader :options
50
+ # @return [Status]
51
+ attr_reader :status
52
+ def initialize(session, number)
53
+ @session, @number = session, number
54
+ @options = OptionsList.new(:window, self, false)
55
+ @status = Status.new(self)
56
+ end
57
+
58
+ def session=(new_session)
59
+ i = -1
60
+ first_try = true
61
+ begin
62
+ num = (first_try ? @number : (i += 1))
63
+ move(new_session, num)
64
+ rescue IndexInUse
65
+ first_try = false
66
+ retry
67
+ end
68
+ end
69
+
70
+ def number=(new_number)
71
+ move(@session, new_number)
72
+ end
73
+
74
+ # Moves the window to either a different session, a different
75
+ # position or both.
76
+ #
77
+ # @param [Session] new_session
78
+ # @param [Number] new_number
79
+ #
80
+ # @return [void]
81
+ # @raise [Exception::IndexInUse]
82
+ # @see #number=
83
+ # @see #session=
84
+ #
85
+ # @tmux move-window
86
+ def move(new_session, new_number)
87
+ return if @session == new_session && @number == new_number
88
+ target = "%s:%s" % [new_session.identifier, new_number]
89
+
90
+ res = server.invoke_command("move-window -s #{identifier} -t #{target}")
91
+ if res =~ /^can't move window: index in use: \d+/
92
+ raise IndexInUse, [new_session, new_number]
93
+ end
94
+ @session = new_session
95
+ @number = new_number
96
+ end
97
+
98
+ def <=>(other)
99
+ return nil unless other.is_a?(Window)
100
+ [@session, @number] <=> [other.session, other.number]
101
+ end
102
+
103
+ # @return [Boolean]
104
+ def ==(other)
105
+ self.class == other.class && @session == other.session && @number == other.number
106
+ end
107
+
108
+ # @return [Number]
109
+ def hash
110
+ [@session.hash, @number].hash
111
+ end
112
+
113
+ # @return [Boolean]
114
+ def eql?(other)
115
+ self == other
116
+ end
117
+
118
+ # @return [Server]
119
+ attr_reader :server
120
+ undef_method "server"
121
+ def server
122
+ @session.server
123
+ end
124
+
125
+ # @return [String]
126
+ # @tmuxver &gt;=1.1
127
+ # @tmux rename-window
128
+ attr_accessor :name
129
+ undef_method "name"
130
+ undef_method "name="
131
+ def name
132
+ server.check_for_version!("1.1")
133
+
134
+ @session.windows_information[@number][:name]
135
+ end
136
+
137
+ def name=(value)
138
+ # TODO escape name?
139
+ server.invoke_command "rename-window -t #{identifier} '#{value}'"
140
+ end
141
+
142
+ # @return [Integer]
143
+ # @tmuxver &gt;=1.1
144
+ attr_reader :width
145
+ undef_method "width"
146
+ def width
147
+ server.check_for_version!("1.1")
148
+
149
+ @session.windows_information[@number][:width]
150
+ end
151
+
152
+ # @return [Integer]
153
+ # @tmuxver &gt;=1.1
154
+ attr_reader :height
155
+ undef_method "height"
156
+ def height
157
+ server.check_for_version!("1.1")
158
+
159
+ @session.windows_information[@number][:height]
160
+ end
161
+
162
+ # @return [String]
163
+ attr_reader :identifier
164
+ undef_method "identifier"
165
+ def identifier
166
+ "%s:%s" % [@session.identifier, @number]
167
+ end
168
+
169
+ # Aggressively resize the window. This means that tmux will resize
170
+ # the window to the size of the smallest {Session session} for
171
+ # which it is the current window, rather than the smallest
172
+ # {Session session} to which it is attached. The window may resize
173
+ # when the current window is changed on another {Session session};
174
+ # this option is good for full-screen programs which support
175
+ # SIGWINCH and poor for interactive programs such as shells.
176
+ #
177
+ # @return [Boolean]
178
+ attr_accessor :aggressive_resize
179
+ undef_method "aggressive_resize"
180
+ undef_method "aggressive_resize="
181
+ def aggressive_resize
182
+ @options.aggressive_resize
183
+ end
184
+ alias_method :aggressive_resize?, :aggressive_resize
185
+
186
+ def aggressive_resize=(bool)
187
+ @options.aggressive_resize = bool
188
+ end
189
+
190
+ # Control automatic window renaming. When this setting is enabled,
191
+ # tmux will attempt – on supported platforms – to rename the
192
+ # window to reflect the command currently running in it. This flag
193
+ # is automatically disabled for an individual window when a name
194
+ # is specified at creation with {Session#create_window} or
195
+ # {Server#create_session}, or later with {#name=}.
196
+ #
197
+ # @return [Boolean]
198
+ attr_accessor :automatic_rename
199
+ undef_method "automatic_rename"
200
+ undef_method "automatic_rename="
201
+ def automatic_rename
202
+ @options.automatic_rename
203
+ end
204
+ alias_method :automatic_rename?, :automatic_rename
205
+
206
+ def automatic_rename=(bool)
207
+ @options.automatic_rename = bool
208
+ end
209
+
210
+ # Duplicate input to any {Pane pane} to all other {Pane panes} in
211
+ # the same window (only for {Pane panes} that are not in any
212
+ # special mode)
213
+ #
214
+ # @return [Boolean]
215
+ attr_accessor :synchronize_panes
216
+ undef_method "synchronize_panes"
217
+ undef_method "synchronize_panes="
218
+ def synchronize_panes
219
+ @options.synchronize_panes
220
+ end
221
+ alias_method :synchronize_panes?, :synchronize_panes
222
+
223
+ def synchronize_panes=(bool)
224
+ @options.synchronize_panes = bool
225
+ end
226
+
227
+ # A window with this flag set is not destroyed when the program
228
+ # running in it exits. The window may be reactivated with
229
+ # {#respawn}.
230
+ #
231
+ # @return [Boolean]
232
+ attr_accessor :remain_on_exit
233
+ undef_method "remain_on_exit"
234
+ undef_method "remain_on_exit="
235
+ def remain_on_exit
236
+ @options.remain_on_exit
237
+ end
238
+ alias_method :remain_on_exit?, :remain_on_exit
239
+
240
+ def remain_on_exit=(bool)
241
+ @options.remain_on_exit = bool
242
+ end
243
+
244
+ # Instructs tmux to expect UTF-8 sequences to appear in this
245
+ # window.
246
+ #
247
+ # @return [Boolean]
248
+ attr_accessor :utf8
249
+ undef_method "utf8"
250
+ undef_method "utf8="
251
+ def utf8
252
+ @options.utf8
253
+ end
254
+ alias_method :utf8?, :utf8
255
+
256
+ def utf8=(bool)
257
+ @options.utf8 = bool
258
+ end
259
+
260
+ # Monitor for activity in the window. Windows with activity are
261
+ # highlighted in the {StatusBar status line}.
262
+ #
263
+ # @return [Boolean]
264
+ attr_accessor :monitor_activity
265
+ undef_method "monitor_activity"
266
+ undef_method "monitor_activity="
267
+ def monitor_activity
268
+ @options.monitor_activity
269
+ end
270
+ alias_method :monitor_activity?, :monitor_activity
271
+
272
+ def monitor_activity=(bool)
273
+ @options.monitor_activity = bool
274
+ end
275
+
276
+ # Monitor content in the window. When the
277
+ # {http://linux.die.net/man/3/fnmatch fnmatch(3)} pattern appears
278
+ # in the window, it is highlighted in the {StatusBar status line}.
279
+ #
280
+ # @return [String]
281
+ attr_accessor :monitor_content
282
+ undef_method "monitor_content"
283
+ undef_method "monitor_content="
284
+ def monitor_content
285
+ @options.monitor_content
286
+ end
287
+
288
+ def monitor_content=(pattern)
289
+ @options.monitor_content = pattern
290
+ end
291
+
292
+ # Prevent tmux from resizing the window to greater than
293
+ # `max_width`. A value of zero restores the default unlimited
294
+ # setting.
295
+ #
296
+ # @return [Number]
297
+ attr_accessor :max_width
298
+ undef_method "max_width"
299
+ undef_method "max_width="
300
+ def max_width
301
+ @options.force_width
302
+ end
303
+
304
+ def max_width=(value)
305
+ @options.force_width = value
306
+ end
307
+ alias_method :force_width, :max_width
308
+ alias_method :force_width=, "max_width="
309
+
310
+ # Prevent tmux from resizing the window to greater than
311
+ # `max_height`. A value of zero restores the default unlimited
312
+ # setting.
313
+ #
314
+ # @return [Number]
315
+ attr_accessor :max_height
316
+ undef_method "max_height"
317
+ undef_method "max_height="
318
+ def max_height
319
+ @options.force_height
320
+ end
321
+
322
+ def max_height=(value)
323
+ @options.force_height = value
324
+ end
325
+ alias_method :force_height, :max_height
326
+ alias_method :force_height=, "max_height="
327
+
328
+ # If this option is set to true, tmux will generate
329
+ # {http://linux.die.net/man/1/xterm xterm(1)}-style function key
330
+ # sequences. These have a number included to indicate modifiers
331
+ # such as Shift, Alt or Ctrl. The default is false.
332
+ #
333
+ # @return [Boolean]
334
+ attr_accessor :xterm_keys
335
+ undef_method "xterm_keys"
336
+ undef_method "xterm_keys="
337
+ def xterm_keys
338
+ @options.xterm_keys
339
+ end
340
+ alias_method :xterm_keys?, :xterm_keys
341
+
342
+ def xterm_keys=(bool)
343
+ @options.xterm_keys = bool
344
+ end
345
+
346
+ # Sets the window's conception of what characters are considered
347
+ # word separators, for the purposes of the next and previous word
348
+ # commands in {Pane#copy_mode copy mode}. The default is `[" ",
349
+ # "-", "_", "@"]`.
350
+ #
351
+ # @return [Array<String>]
352
+ attr_accessor :word_separators
353
+ undef_method "word_separators"
354
+ undef_method "word_separators="
355
+ def word_separators
356
+ @options.word_separators
357
+ end
358
+
359
+ def word_separators=(value)
360
+ @options.word_separators = value
361
+ end
362
+
363
+ # This option configures whether programs running inside tmux may
364
+ # use the terminal alternate screen feature, which allows the
365
+ # smcup and rmcup {http://linux.die.net/man/5/terminfo
366
+ # terminfo(5)} capabilities to be issued to preserve the existing
367
+ # window content on start and restore it on exit.
368
+ #
369
+ # @return [Boolean]
370
+ attr_accessor :alternate_screen
371
+ undef_method "alternate_screen"
372
+ undef_method "alternate_screen="
373
+ def alternate_screen
374
+ @options.alternate_screen
375
+ end
376
+ alias_method :alternate_screen?, :alternate_screen
377
+
378
+ def alternate_screen=(bool)
379
+ @options.alternate_screen = bool
380
+ end
381
+
382
+ # Mouse state in modes. If true, the mouse may be used to copy a
383
+ # selection by dragging in {Pane#copy_mode copy mode}, or to
384
+ # select an option in choice mode.
385
+ #
386
+ # @return [Boolean]
387
+ attr_accessor :mode_mouse
388
+ undef_method "mode_mouse"
389
+ undef_method "mode_mouse="
390
+ def mode_mouse
391
+ @options.mode_mouse
392
+ end
393
+ alias_method :mode_mouse?, :mode_mouse
394
+
395
+ def mode_mouse=(bool)
396
+ @options.mode_mouse = bool
397
+ end
398
+
399
+ # Clock color.
400
+ #
401
+ # @return [Symbol]
402
+ attr_accessor :clock_mode_color
403
+ undef_method "clock_mode_color"
404
+ undef_method "clock_mode_color="
405
+ def clock_mode_color
406
+ @options.clock_mode_colour
407
+ end
408
+ alias_method :clock_mode_colour, :clock_mode_color
409
+
410
+ def clock_mode_color=(color)
411
+ @options.clock_mode_colour = color
412
+ end
413
+ alias_method :clock_mode_colour=, "clock_mode_color="
414
+
415
+ # Clock hour format.
416
+ #
417
+ # @return [Symbol<:twelve, :twenty_four>]
418
+ attr_accessor :clock_mode_style
419
+ undef_method "clock_mode_style"
420
+ undef_method "clock_mode_style="
421
+
422
+ def clock_mode_style
423
+ @options.clock_mode_style
424
+ end
425
+
426
+ def clock_mode_style=(style)
427
+ @options.clock_mode_style = style
428
+ end
429
+
430
+ # Set the height of the main (left or top) pane in the
431
+ # main-horizontal or main-vertical {#layout= layouts}.
432
+ #
433
+ # @return [Number]
434
+ # @see #layout=
435
+ attr_accessor :main_pane_height
436
+ undef_method "main_pane_height"
437
+ undef_method "main_pane_height="
438
+ def main_pane_height
439
+ @options.main_pane_height
440
+ end
441
+
442
+ def main_pane_height=(height)
443
+ @options.main_pane_height = height
444
+ end
445
+
446
+ # Set the width of the main (left or top) pane in the
447
+ # main-horizontal or main-vertical {#layout= layouts}.
448
+ #
449
+ # @return [Number]
450
+ # @see #layout=
451
+ attr_accessor :main_pane_width
452
+ undef_method "main_pane_width"
453
+ undef_method "main_pane_width="
454
+ def main_pane_width
455
+ @options.main_pane_width
456
+ end
457
+
458
+ def main_pane_width=(width)
459
+ @options.main_pane_width = width
460
+ end
461
+
462
+ # @return [Symbol]
463
+ attr_accessor :mode_attr
464
+ undef_method "mode_attr"
465
+ undef_method "mode_attr="
466
+ def mode_attr
467
+ @options.mode_attr
468
+ end
469
+
470
+ def mode_attr=(attr)
471
+ @options.mode_attr = attr
472
+ end
473
+
474
+ # @return [Symbol]
475
+ attr_accessor :mode_bg
476
+ undef_method "mode_bg"
477
+ undef_method "mode_bg="
478
+ def mode_bg
479
+ @options.mode_bg
480
+ end
481
+
482
+ def mode_bg=(bg)
483
+ @options.mode_bg = bg
484
+ end
485
+
486
+ # @return [Symbol]
487
+ attr_accessor :mode_fg
488
+ undef_method "mode_fg"
489
+ undef_method "mode_fg="
490
+ def mode_fg
491
+ @options.mode_fg
492
+ end
493
+
494
+ def mode_fg=(fg)
495
+ @options.mode_fg = fg
496
+ end
497
+
498
+ # @return [Symbol]
499
+ attr_accessor :mode_keys
500
+ undef_method "mode_keys"
501
+ undef_method "mode_keys="
502
+ def mode_keys
503
+ @options.mode_keys
504
+ end
505
+
506
+ def mode_keys=(keymap)
507
+ @options.mode_keys = keymap
508
+ end
509
+
510
+ # Kills the window.
511
+ # @tmux kill-window
512
+ # @return [void]
513
+ def kill
514
+ server.invoke_command "kill-window -t #{identifier}"
515
+ end
516
+
517
+ # Rotates the positions of the {Pane panes} within a window.
518
+ #
519
+ # @tmux rotate-window
520
+ # @return [void]
521
+ def rotate(direction = :upward)
522
+ flag = case direction
523
+ when :upward
524
+ "U"
525
+ when :downward
526
+ "D"
527
+ else
528
+ raise ArgumentError
529
+ end
530
+ server.invoke_command "rotate-window -#{flag} -t #{identifier}"
531
+ end
532
+
533
+ # @todo attr_reader
534
+ # @param [Symbol<:even_horizontal, :even_vertical, :main_horizontal, :main_vertical] The layout to apply to the window
535
+ # @return [Symbol]
536
+ # @tmux select-layout
537
+ # @tmuxver &gt;=1.3 for :tiled layout
538
+ # @tmuxver &gt;=1.0 for all other layouts
539
+ attr_writer :layout
540
+ undef_method "layout="
541
+ def layout=(layout)
542
+ server.check_for_version!("1.0")
543
+ raise Exception::UnsupportedVersion, "1.3" if layout == :tiled && server.version < "1.3"
544
+
545
+ valid_layouts = [:even_horizontal, :even_vertical, :main_horizontal, :main_vertical, :tiled]
546
+ raise ArgumentError unless valid_layouts.include?(layout)
547
+ layout = layout.to_s.tr("_", "-")
548
+ server.invoke_command "select-layout -t #{identifier} #{layout}"
549
+ end
550
+
551
+ # @param [Hash] search Filters the resulting hash using {FilterableHash#filter}
552
+ # @return [Hash] A hash with information for all panes
553
+ # @tmux list-panes
554
+ # @tmuxver &gt;=1.1
555
+ def panes_information(search={})
556
+ server.check_for_version!("1.1")
557
+
558
+ hash = {}
559
+ output = server.invoke_command "list-panes -t #{identifier}"
560
+ output.each_line do |pane|
561
+ params = pane.match(/^(?<num>\d+): \[(?<width>\d+)x(?<height>\d+)\] \[history (?<cur_history>\d+)\/(?<max_history>\d+), (?<memory>\d+) bytes\](?<active> \(active\))?$/)
562
+ num = params[:num].to_i
563
+ width = params[:width].to_i
564
+ height = params[:height].to_i
565
+ cur_history = params[:cur_history].to_i
566
+ max_history = params[:max_history].to_i
567
+ memory = Filesize.new(params[:memory].to_i)
568
+
569
+ # this flag requires tmux >=1.4
570
+ active = !params[:active].nil?
571
+
572
+ hash[num] = {
573
+ :num => num,
574
+ :width => width,
575
+ :height => height,
576
+ :cur_history => cur_history,
577
+ :max_history => max_history,
578
+ :memory => memory,
579
+ :active => active,
580
+ }
581
+ end
582
+ hash.extend FilterableHash
583
+ hash.filter(search)
584
+ end
585
+
586
+ # @return [Array<Pane>] All {Pane panes}
587
+ # @tmuxver &gt;=1.1
588
+ attr_reader :panes
589
+ undef_method "panes"
590
+ def panes
591
+ server.check_for_version!("1.1")
592
+
593
+ panes_information.map do |num, information|
594
+ Pane.new(self, num)
595
+ end
596
+ end
597
+
598
+ # Pastes a {Buffer buffer} into the window.
599
+ #
600
+ # @param [Buffer] buffer The {Buffer buffer} to paste
601
+ # @param pop (see Buffer#paste)
602
+ # @param translate (see Buffer#paste)
603
+ # @param separator (see Buffer#paste)
604
+ # @return [void]
605
+ # @tmux paste-buffer
606
+ # @see Buffer#paste
607
+ # @see Pane#paste
608
+ def paste(buffer, pop = false, translate = true, separator = nil)
609
+ buffer.paste(self, pop, translate, separator)
610
+ end
611
+
612
+ # Select the window.
613
+ #
614
+ # @return [void]
615
+ # @tmux select-window
616
+ def select
617
+ server.invoke_command "select-window -t #{identifier}"
618
+ end
619
+
620
+ # Swap the window with another one.
621
+ #
622
+ # @param [Window] window The window to swap with
623
+ # @return [void]
624
+ # @tmux swap-window
625
+ def swap_with(window)
626
+ server.invoke_command "swap-window -s #{identifier} -t #{window.identifier}"
627
+ end
628
+
629
+ # @param [Symbol<:never, :if_same_window, :always>] return_if When
630
+ # to return the current pane.
631
+ #
632
+ # Note: In tmux versions prior to 1.4, :always can lead to flickering
633
+ # Note: Since tmux version 1.4, :always is forced
634
+ # @return [Pane, nil] The current pane
635
+ attr_reader :current_pane
636
+ undef_method "current_pane"
637
+ def current_pane(return_if = :always)
638
+ if server.version >= "1.4"
639
+ self.panes.find(&:active?)
640
+ else
641
+ # In tmux <1.4, we can only determine the selected pane of the
642
+ # current window.
643
+ #
644
+ # If the user specified return_if = :always, we select this
645
+ # window (if it is not already selected), determine the
646
+ # current pane and select the lastly selected window again.
647
+ cur_window = self.session.any_client.current_window
648
+ same_window = cur_window == self
649
+ return_if_b = ((return_if == :if_same_window && same_window) || (return_if == :always))
650
+
651
+ self.select if return_if_b && !same_window
652
+
653
+ new_pane = nil
654
+ if return_if_b
655
+ num = server.invoke_command("display -p -t #{self.session.any_client.identifier} '#P'").chomp
656
+ new_pane = Pane.new(self, num)
657
+ end
658
+
659
+ if return_if == :always && !same_window
660
+ self.session.select_previous_window
661
+ end
662
+
663
+ return new_pane if new_pane
664
+ end
665
+ end
666
+
667
+ # Select the previously selected pane.
668
+ #
669
+ # @param return_if (see Window#current_pane)
670
+ # @return (see Window#current_pane)
671
+ # @tmux last-pane
672
+ # @tmuxver &gt;=1.4
673
+ def select_last_pane(return_if = :always)
674
+ server.invoke_command("last-pane -t #{identifier}")
675
+ current_pane(return_if)
676
+ end
677
+
678
+ # Reactivates a window in which the command has exited.
679
+ #
680
+ # @param [String, nil] command The command to use to respawn the
681
+ # window. If nil, the command used when the window was created is
682
+ # executed.
683
+ # @param [Boolean] kill Unless `kill` is true, only inactive windows can be respawned
684
+ # @return [void]
685
+ # @tmux respawn-window
686
+ # @see #remain_on_exit
687
+ # @todo escape command
688
+ def respawn(command = nil, kill = false)
689
+ flags = []
690
+ flags << "-k" if kill
691
+ flags << "-t #{identifier}"
692
+ flags << "\"#{command}\"" if command
693
+
694
+ server.invoke_command "respawn-window #{flags.join(" ")}"
695
+ end
696
+ end
697
+ end