muxr 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +46 -0
- data/LICENSE.txt +21 -0
- data/README.md +211 -0
- data/bin/muxr +137 -0
- data/lib/muxr/application.rb +669 -0
- data/lib/muxr/client.rb +145 -0
- data/lib/muxr/command_dispatcher.rb +65 -0
- data/lib/muxr/drawer.rb +44 -0
- data/lib/muxr/input_handler.rb +218 -0
- data/lib/muxr/layout_manager.rb +91 -0
- data/lib/muxr/pane.rb +52 -0
- data/lib/muxr/protocol.rb +73 -0
- data/lib/muxr/pty_process.rb +92 -0
- data/lib/muxr/renderer.rb +468 -0
- data/lib/muxr/session.rb +87 -0
- data/lib/muxr/terminal.rb +817 -0
- data/lib/muxr/version.rb +3 -0
- data/lib/muxr/window.rb +110 -0
- data/lib/muxr.rb +18 -0
- data/muxr.gemspec +42 -0
- metadata +99 -0
data/lib/muxr/version.rb
ADDED
data/lib/muxr/window.rb
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
module Muxr
|
|
2
|
+
# A Window is a single logical "screen" containing an ordered list of panes,
|
|
3
|
+
# a focused-index, a master-index (which pane is the master for tall/grid
|
|
4
|
+
# layouts), and the currently-selected layout.
|
|
5
|
+
class Window
|
|
6
|
+
LAYOUTS = LayoutManager::LAYOUTS
|
|
7
|
+
|
|
8
|
+
attr_accessor :name, :layout, :master_index
|
|
9
|
+
attr_reader :panes, :focused_index
|
|
10
|
+
|
|
11
|
+
def initialize(name: "main")
|
|
12
|
+
@name = name
|
|
13
|
+
@panes = []
|
|
14
|
+
@focused_index = 0
|
|
15
|
+
@last_focused_pane = nil
|
|
16
|
+
@master_index = 0
|
|
17
|
+
@layout = :tall
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Setter records the outgoing focused pane (by reference) so focus_last can
|
|
21
|
+
# return to it even after the panes array is reordered (e.g. by
|
|
22
|
+
# promote_to_master).
|
|
23
|
+
def focused_index=(value)
|
|
24
|
+
return if value == @focused_index
|
|
25
|
+
@last_focused_pane = focused_pane
|
|
26
|
+
@focused_index = value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_pane(pane)
|
|
30
|
+
@panes << pane
|
|
31
|
+
pane
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def remove_pane(pane)
|
|
35
|
+
idx = @panes.index(pane)
|
|
36
|
+
return false unless idx
|
|
37
|
+
pane.close
|
|
38
|
+
@panes.delete_at(idx)
|
|
39
|
+
@last_focused_pane = nil if @last_focused_pane == pane
|
|
40
|
+
clamp_indices!
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def focused_pane
|
|
45
|
+
return nil if @panes.empty?
|
|
46
|
+
@panes[@focused_index]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def focus_next
|
|
50
|
+
return if @panes.empty?
|
|
51
|
+
self.focused_index = (@focused_index + 1) % @panes.length
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def focus_prev
|
|
55
|
+
return if @panes.empty?
|
|
56
|
+
self.focused_index = (@focused_index - 1) % @panes.length
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def focus_last
|
|
60
|
+
return unless @last_focused_pane
|
|
61
|
+
idx = @panes.index(@last_focused_pane)
|
|
62
|
+
return unless idx
|
|
63
|
+
self.focused_index = idx
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def focus_index(idx)
|
|
67
|
+
return if @panes.empty?
|
|
68
|
+
return unless idx.is_a?(Integer) && idx >= 0 && idx < @panes.length
|
|
69
|
+
self.focused_index = idx
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def promote_to_master
|
|
73
|
+
return if @panes.empty?
|
|
74
|
+
return if @master_index == @focused_index
|
|
75
|
+
# Move the focused pane into the master slot and shift the others down,
|
|
76
|
+
# preserving relative order so tall/grid layouts stay stable.
|
|
77
|
+
pane = @panes.delete_at(@focused_index)
|
|
78
|
+
@panes.unshift(pane)
|
|
79
|
+
@master_index = 0
|
|
80
|
+
@focused_index = 0
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def swap_panes(i, j)
|
|
84
|
+
return if i == j
|
|
85
|
+
return unless @panes[i] && @panes[j]
|
|
86
|
+
@panes[i], @panes[j] = @panes[j], @panes[i]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def cycle_layout
|
|
90
|
+
i = LAYOUTS.index(@layout) || 0
|
|
91
|
+
@layout = LAYOUTS[(i + 1) % LAYOUTS.length]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def set_layout(layout)
|
|
95
|
+
layout = layout.to_sym
|
|
96
|
+
raise ArgumentError, "Unknown layout: #{layout}" unless LAYOUTS.include?(layout)
|
|
97
|
+
@layout = layout
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def clamp_indices!
|
|
101
|
+
if @panes.empty?
|
|
102
|
+
@focused_index = 0
|
|
103
|
+
@master_index = 0
|
|
104
|
+
else
|
|
105
|
+
@focused_index = @focused_index.clamp(0, @panes.length - 1)
|
|
106
|
+
@master_index = @master_index.clamp(0, @panes.length - 1)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/muxr.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative "muxr/version"
|
|
2
|
+
require_relative "muxr/pty_process"
|
|
3
|
+
require_relative "muxr/terminal"
|
|
4
|
+
require_relative "muxr/pane"
|
|
5
|
+
require_relative "muxr/drawer"
|
|
6
|
+
require_relative "muxr/layout_manager"
|
|
7
|
+
require_relative "muxr/window"
|
|
8
|
+
require_relative "muxr/session"
|
|
9
|
+
require_relative "muxr/renderer"
|
|
10
|
+
require_relative "muxr/input_handler"
|
|
11
|
+
require_relative "muxr/command_dispatcher"
|
|
12
|
+
require_relative "muxr/protocol"
|
|
13
|
+
require_relative "muxr/application"
|
|
14
|
+
require_relative "muxr/client"
|
|
15
|
+
|
|
16
|
+
module Muxr
|
|
17
|
+
class Error < StandardError; end
|
|
18
|
+
end
|
data/muxr.gemspec
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require_relative "lib/muxr/version"
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "muxr"
|
|
5
|
+
spec.version = Muxr::VERSION
|
|
6
|
+
spec.authors = ["Roel Bondoc"]
|
|
7
|
+
spec.email = ["rsbondoc@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = "A keyboard-driven terminal multiplexer with tiling layouts and a Quake-style drawer"
|
|
10
|
+
spec.description = <<~DESC
|
|
11
|
+
muxr is a Ruby terminal multiplexer that combines GNU Screen's familiar
|
|
12
|
+
keybindings, xmonad-inspired automatic tiling, and a Quake-style drop-down
|
|
13
|
+
drawer overlay. Panes are treated as tiling clients: layouts are pure
|
|
14
|
+
functions of pane count and screen dimensions, not user-resized regions.
|
|
15
|
+
DESC
|
|
16
|
+
spec.homepage = "https://github.com/roelbondoc/muxr"
|
|
17
|
+
spec.license = "MIT"
|
|
18
|
+
spec.required_ruby_version = ">= 3.4"
|
|
19
|
+
|
|
20
|
+
spec.metadata = {
|
|
21
|
+
"source_code_uri" => "https://github.com/roelbondoc/muxr",
|
|
22
|
+
"bug_tracker_uri" => "https://github.com/roelbondoc/muxr/issues",
|
|
23
|
+
"changelog_uri" => "https://github.com/roelbondoc/muxr/blob/main/CHANGELOG.md",
|
|
24
|
+
"rubygems_mfa_required" => "true",
|
|
25
|
+
"allowed_push_host" => "https://rubygems.org"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
spec.bindir = "bin"
|
|
29
|
+
spec.executables = ["muxr"]
|
|
30
|
+
spec.files = Dir[
|
|
31
|
+
"lib/**/*.rb",
|
|
32
|
+
"bin/muxr",
|
|
33
|
+
"README.md",
|
|
34
|
+
"CHANGELOG.md",
|
|
35
|
+
"LICENSE.txt",
|
|
36
|
+
"muxr.gemspec"
|
|
37
|
+
]
|
|
38
|
+
spec.require_paths = ["lib"]
|
|
39
|
+
|
|
40
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
41
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
42
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: muxr
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Roel Bondoc
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: minitest
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '5.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '5.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '13.0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '13.0'
|
|
40
|
+
description: |
|
|
41
|
+
muxr is a Ruby terminal multiplexer that combines GNU Screen's familiar
|
|
42
|
+
keybindings, xmonad-inspired automatic tiling, and a Quake-style drop-down
|
|
43
|
+
drawer overlay. Panes are treated as tiling clients: layouts are pure
|
|
44
|
+
functions of pane count and screen dimensions, not user-resized regions.
|
|
45
|
+
email:
|
|
46
|
+
- rsbondoc@gmail.com
|
|
47
|
+
executables:
|
|
48
|
+
- muxr
|
|
49
|
+
extensions: []
|
|
50
|
+
extra_rdoc_files: []
|
|
51
|
+
files:
|
|
52
|
+
- CHANGELOG.md
|
|
53
|
+
- LICENSE.txt
|
|
54
|
+
- README.md
|
|
55
|
+
- bin/muxr
|
|
56
|
+
- lib/muxr.rb
|
|
57
|
+
- lib/muxr/application.rb
|
|
58
|
+
- lib/muxr/client.rb
|
|
59
|
+
- lib/muxr/command_dispatcher.rb
|
|
60
|
+
- lib/muxr/drawer.rb
|
|
61
|
+
- lib/muxr/input_handler.rb
|
|
62
|
+
- lib/muxr/layout_manager.rb
|
|
63
|
+
- lib/muxr/pane.rb
|
|
64
|
+
- lib/muxr/protocol.rb
|
|
65
|
+
- lib/muxr/pty_process.rb
|
|
66
|
+
- lib/muxr/renderer.rb
|
|
67
|
+
- lib/muxr/session.rb
|
|
68
|
+
- lib/muxr/terminal.rb
|
|
69
|
+
- lib/muxr/version.rb
|
|
70
|
+
- lib/muxr/window.rb
|
|
71
|
+
- muxr.gemspec
|
|
72
|
+
homepage: https://github.com/roelbondoc/muxr
|
|
73
|
+
licenses:
|
|
74
|
+
- MIT
|
|
75
|
+
metadata:
|
|
76
|
+
source_code_uri: https://github.com/roelbondoc/muxr
|
|
77
|
+
bug_tracker_uri: https://github.com/roelbondoc/muxr/issues
|
|
78
|
+
changelog_uri: https://github.com/roelbondoc/muxr/blob/main/CHANGELOG.md
|
|
79
|
+
rubygems_mfa_required: 'true'
|
|
80
|
+
allowed_push_host: https://rubygems.org
|
|
81
|
+
rdoc_options: []
|
|
82
|
+
require_paths:
|
|
83
|
+
- lib
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '3.4'
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
requirements: []
|
|
95
|
+
rubygems_version: 3.6.9
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: A keyboard-driven terminal multiplexer with tiling layouts and a Quake-style
|
|
98
|
+
drawer
|
|
99
|
+
test_files: []
|