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.
@@ -0,0 +1,3 @@
1
+ module Muxr
2
+ VERSION = "0.1.0"
3
+ end
@@ -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: []