Created
September 1, 2009 14:44
-
-
Save dgfitch/179128 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# focus - convenient window switching in ratpoison | |
# | |
# Dan Fitch [email protected] | |
# | |
# based on select.sh - originally copyright 2003 <[email protected]> | |
# | |
# Example: focus cmus in a screen or start a new one containing it | |
# | |
# bind a exec focus 'cmus' 'screen cmus' | |
# | |
# USAGE: | |
# | |
# focus <operation> <type> <regex> | |
# | |
# Returns 1 if nothing matches. | |
# | |
# When operation is "last": | |
# re-run the last regex with the given type | |
# When operation is "select": | |
# toggle the two most recently accessed matching windows | |
# When operation is "cycle": | |
# go through all of the matching windows in order | |
# When operation is "cycleback": | |
# go through all of the matching windows in order, backwards | |
# When operation is "menu": | |
# show menu of all of the matching windows | |
# | |
# When type is "last": | |
# re-run the last regex with the given operation | |
# When type is "title": | |
# match by title | |
# When type is "class": | |
# match by class | |
# | |
# If the window has a screen session, attempt to select the first matching screen | |
# | |
# TODO: | |
# menu mode | |
# ordering is a little wacky on simple focus, like it's skipping when it shouldn't have to | |
# use knowledge of screens (the physical ones) | |
# | |
$: << File.dirname(__FILE__) | |
require 'ratpoison' | |
windows = Ratpoison.windows_array | |
operation = nil | |
type = nil | |
args = nil | |
if ARGV[0] == "last" | |
operation = Ratpoison.getenv "focus_last_operation" | |
args = Ratpoison.getenv "focus_last_args" | |
else | |
operation = ARGV[0] | |
Ratpoison.setenv "focus_last_operation #{operation}" | |
end | |
if ARGV[1] == "last" | |
type = Ratpoison.getenv "focus_last_type" | |
args = Ratpoison.getenv "focus_last_args" | |
else | |
type = ARGV[1] | |
Ratpoison.setenv "focus_last_type #{type}" | |
end | |
if not args | |
exit 2 if not ARGV[2] | |
args = ARGV[2..-1].join(' ') | |
Ratpoison.setenv "focus_last_args #{args}" | |
end | |
regex = /#{args}/i | |
current_window = windows.detect {|x| x.status == "*"} | |
filtered_windows = windows.find_all do |win| | |
case type | |
when /title/: | |
regex.match win.title | |
when /class/: | |
regex.match win.class | |
else | |
raise "Unknown match type #{type}" | |
end | |
end | |
if filtered_windows.length == 0 | |
puts "no windows match #{type} #{regex}" | |
exit 1 | |
end | |
# TODO: This should probably build a list of all screen titles that match so | |
# that cycling works at screen granularity instead of window granularity | |
window = case operation | |
when /cycle/: | |
# Cycle things that match | |
if filtered_windows.detect { |x| x.number == current_window.number } | |
# Select by number | |
cycle = filtered_windows.sort_by { |x| x.number } | |
current_index = cycle.index current_window | |
index = | |
if current_index | |
if operation[/back/]: | |
current_index + 1 | |
else | |
current_index - 1 | |
end | |
else | |
0 | |
end | |
puts "selecting #{index} by number, current is #{current_index}" if $DEBUG | |
else | |
# Current window does not match -- select the most recent or least recent | |
cycle = filtered_windows.sort_by { |x| x.last_access } | |
index = | |
if operation[/back/]: | |
0 | |
else | |
cycle.length - 1 | |
end | |
puts "selecting #{index} by recent" if $DEBUG | |
end | |
index = cycle.length - 1 if index < 0 | |
index = 0 if index > cycle.length - 1 | |
puts "moving to #{index}" if $DEBUG | |
cycle[index] | |
when /menu/: | |
# Select via menu (TODO) | |
menu = filtered_windows.sort_by { |x| x.last_access } | |
if menu.length == 1 then | |
menu[0] | |
else | |
nil | |
end | |
else | |
# Select the most recent non-current window | |
select = filtered_windows.sort_by { |x| x.last_access } | |
if current_window | |
select.delete_if { |x| x.number == current_window.number } | |
end | |
if select.length == 0 | |
nil | |
else | |
puts select.map { |x| "#{x.number} #{x.title}" } if $DEBUG | |
select[0] | |
end | |
end | |
Ratpoison.select window.number if window | |
window ||= current_window | |
if window and window.screen_session | |
screen = window.screen_session.detect { |x| regex.match x.title } | |
exit 1 if window == current_window and screen.number == window.screen_session.number | |
Ratpoison::ScreenSession.select screen.number if screen | |
else | |
exit 1 if window == current_window | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment