Skip to content

Instantly share code, notes, and snippets.

@SamSaffron
Created March 25, 2019 04:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SamSaffron/dea99376d25394b5337e5925079ef420 to your computer and use it in GitHub Desktop.
Save SamSaffron/dea99376d25394b5337e5925079ef420 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'i3ipc'
class I3Helper
def initialize
@i3 = I3Ipc::Connection.new
end
def tree
@tree ||= @i3.tree
end
def recurse(nodes = nil, focused: false, floating: false, depth: 0, &blk)
nodes ||= tree.nodes
nodes.each do |n|
blk.call n, focused: n.focused || focused, depth: depth, floating: floating
depth += 1
recurse(n.nodes, depth: depth, floating: floating, &blk)
recurse(n.floating_nodes, depth: depth, floating: true, &blk)
end
end
def is_floating?
recurse(tree.nodes) do |n, focused: f|
if n.respond_to? :window_properties
return n.floating == "user_on" if f
end
end
end
def layout_exec(command, cols: 2, rows: 3, balance: :auto)
windows = []
focused_window = nil
focused_workspace = nil
workspace = nil
recurse do |n, depth: , focused: , floating:|
# dim = n.type == "con" ? " #{n.rect.width}x#{n.rect.height}" : ""
# puts "#{" " * depth} #{n.name} #{n.type}#{dim} #{n.layout} #{focused ? "*" : ""} #{floating ? "f" : ""}"
workspace = n.name if n.type == "workspace"
if n.respond_to?(:window_properties) && !floating
windows << {window: n, workspace: workspace}
if focused
focused_window = n if focused
focused_workspace = workspace
end
end
end
if !focused_window
@i3.command("exec #{command}")
return
end
windows = windows.select do |window:, workspace:|
workspace == focused_workspace && window.output == focused_window.output && window.window_properties.instance != "i3bar"
end.map do |window:, workspace:|
window
end
if balance == :auto && windows.length > 0
outputs = @i3.outputs.sort{|a,b| a.rect.x <=> b.rect.x}
left_aligns = []
take = false
outputs.each do |output|
left_aligns << output.name if take
take = true if output.primary
end
if left_aligns.include?(windows[0].output)
balance = :left
end
end
if windows.length < cols
@i3.command("split h; exec #{command}")
else
full_cols = (windows.length - cols) / (rows - 1)
full_rows = (windows.length - cols) % (rows - 1)
index = cols - full_cols - 1
if balance == :left
index = full_cols * rows
end
window = windows[index]
split = full_rows == 0 ? " split v;" : ""
@i3.command("[con_id=\"#{window.id}\"] focus; #{split} exec #{command}")
end
#p @i3.outputs
end
def move(dir)
@i3.command("mark _last")
if is_floating?
@i3.command("move to output #{dir}")
else
@i3.command("move #{dir}")
end
@i3.command('[con_mark="_last"] focus')
end
def close
@i3.close
@i3 = nil
end
end
helper = I3Helper.new
# layout-exec -cols 3 -rows 3
case ARGV[0]
when "layout_exec" then
helper.layout_exec "i3-sensible-terminal"
when "move_left" then
helper.move("left")
when "move_right" then
helper.move("right")
else
puts "unknown command"
exit 1
end
helper.close
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment