wmiirc-rumai

git clone git://oldgit.suckless.org/wmiirc-rumai/
Log | Files | Refs | README | LICENSE

commit c41e3678e0d3e0558fc56732de6b2e49e9ddea9b
parent 9052026fa3f0f0b05c66543f3cf264fed998f837
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date:   Thu, 26 Apr 2007 23:56:47 -0700

incorporate boroir's improvements to mini DSL and do some clean up

Diffstat:
wmiirc | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
wmiirc-config.rb | 242++++++++++++++++++++-----------------------------------------------------------
2 files changed, 192 insertions(+), 215 deletions(-)

diff --git a/wmiirc b/wmiirc @@ -1,55 +1,154 @@ #!/usr/bin/ruby -w # Loader for ruby-based wmii configuration. #-- -# Copyright 2006 Suraj N. Kurapati +# Copyright 2006-2007 Suraj N. Kurapati +# Copyright 2007 Nick Stenning # See the file named LICENSE for details. -require 'logger' +# load the wmii-irb library + $: << File.join(File.dirname(__FILE__), 'wmii-irb') + require 'wm' -# Provide a means by which the user can rescue themselves after an exception. -def throw_life_saver aError - system 'xterm &' + include Wmii - IO.popen('xmessage -file - -buttons "recover from error:0,ignore this message:1"', 'w') do |f| - f.puts aError.inspect, aError.backtrace - end - - system($0 + ' &') if $?.exitstatus == 0 -end +# create a logger to aid debugging + require 'logger' + LOG = Logger.new(__FILE__ + '.log', 5) -LOG = Logger.new(__FILE__ + '.log', 5) -class << LOG - alias write << -end + # capture standard output in logger + class << LOG + alias write << # emulate IO.write + end + $stdout = $stderr = LOG LOG.info "birth" -# terminate existing instances of this program - system 'wmiir xwrite /event Start wmiirc' # terminate them nicely +begin + # Miniature DSL to ease configuration. - instances = `ps -C #{File.basename $0} -o pid h`.split.map! {|s| s.to_i} - instances.delete $$ # do not kill self! + class Handler < Hash + def handle aKey, *aArgs, &aBlock + if block_given? + self[aKey] = aBlock + elsif key? aKey + self[aKey].call(*aArgs) + end + end + end - instances.each do |pid| - LOG.info "slaying ##{pid}" - Process.kill :SIGKILL, pid - end + EVENTS = Handler.new + ACTIONS = Handler.new + KEYS = Handler.new -# load the configuration - Thread.abort_on_exception = true + def event *a, &b + EVENTS.handle(*a, &b) + end - begin - $stdout = $stderr = LOG + def action *a, &b + ACTIONS.handle(*a, &b) + end + + def key *a, &b + a.map! { |x| x.respond_to?(:flatten) ? x.flatten.join('-') : x } + KEYS.handle a.join(','), &b + end + + # Utility functions + + # Shows a menu with the given items and returns the chosen item. + # If nothing was chosen, then *nil* is returned. + def show_menu aChoices, aPrompt = nil + cmd = "dmenu -b -fn #{WMII_FONT.inspect} " << + %w[-nf -nb -sf -sb].zip( + Color::NORMAL.split[0,2] + Color::FOCUSED.split[0,2] + ).flatten!.map! {|s| s.inspect}.join(' ') + + cmd << " -p #{aPrompt.to_s.inspect}" if aPrompt + + IO.popen cmd, 'r+' do |menu| + menu.puts aChoices + menu.close_write + + choice = menu.read + choice unless choice.empty? + end + end + + + require 'find' + + # Returns the names of programs present in the given directories. + def find_programs aDirs + aDirs = aDirs.map {|p| File.expand_path p} + names = [] + + Find.find(*aDirs) do |f| + if File.file? f and File.executable? f + names << File.basename(f) + end + end + + names.uniq.sort + end + + # terminate existing instances of this program + fs.event << 'Start wmiirc' + + event :Start do |arg| + exit if arg == 'wmiirc' + end + + # load user's configuration file load File.join(File.dirname(__FILE__), 'wmiirc-config.rb') - rescue => e - LOG.error e - throw_life_saver e + # Tag bar setup + fs.lbar.clear + + tags.each do |tag| + color = (tag == current_tag) ? Color::FOCUSED : Color::NORMAL + + bar = fs.lbar[tag] + bar.create + bar.write "#{color} #{tag}" + end + + # Keygrab setup + fs.keys = KEYS.keys.join("\n") + + event :Key do |*args| + key(*args) + end - rescue Exception => e - LOG.fatal e - end + # Event loop + fs.event.open do |bus| + loop do + bus.read.split("\n").each do |event| + type, parms = event.split(' ', 2) + + args = parms.split(' ') rescue [] + event type.to_sym, *args + end + end + end + +rescue => e + LOG.error e + + # allow the user to rescue themselves + system 'xterm &' + + IO.popen('xmessage -file - -buttons recover:0,ignore:1', 'w') do |f| + f.puts e.inspect, e.backtrace + end + + if $?.exitstatus == 0 + system $0 + ' &' + end + +rescue Exception => e + LOG.fatal e +end LOG.info "death" diff --git a/wmiirc-config.rb b/wmiirc-config.rb @@ -3,88 +3,6 @@ # Copyright 2006-2007 Suraj N. Kurapati # See the file named LICENSE for details. - -# load the wmii-irb library -$: << File.join(File.dirname(__FILE__), 'wmii-irb') -require 'wm' -include Wmii - - -################################################################################ -# Miniature DSL to ease configuration. -# Adapted from Kris Maglione and borior. -################################################################################ - -class HandlerHash < Hash - def handle aKey, *aArgs, &aBlock - if block_given? - self[aKey] = aBlock - elsif key? aKey - self[aKey].call(*aArgs) - end - end -end - -EVENTS = HandlerHash.new -ACTIONS = HandlerHash.new -SHORTCUTS = HandlerHash.new - -def event *a, &b - EVENTS.handle(*a, &b) -end - -def action *a, &b - ACTIONS.handle(*a, &b) -end - -def shortcut *a, &b - SHORTCUTS.handle(*a, &b) -end - - -################################################################################ -# Utility functions -################################################################################ - -# Shows a menu with the given items and returns the chosen item. -# If nothing was chosen, then *nil* is returned. -def show_menu aChoices, aPrompt = nil - cmd = "dmenu -b -fn #{WMII_FONT.inspect} " << - %w[-nf -nb -sf -sb].zip( - Color::NORMAL.split[0,2] + Color::FOCUSED.split[0,2] - ).flatten!.map! {|s| s.inspect}.join(' ') - - cmd << " -p #{aPrompt.to_s.inspect}" if aPrompt - - IO.popen cmd, 'r+' do |menu| - menu.puts aChoices - menu.close_write - - choice = menu.read - choice unless choice.empty? - end -end - - -require 'find' - -# Returns the names of programs present in the given directories. -def find_programs aDirs - aDirs = aDirs.map {|p| File.expand_path p} - names = [] - - Find.find(*aDirs) do |f| - if File.file? f and File.executable? f - names << File.basename(f) - end - end - - names.uniq! - names.sort! - names -end - - ################################################################################ # GENERAL CONFIGURATION ################################################################################ @@ -108,11 +26,11 @@ module Key end module Mouse - FIRST_CLICK = 1 - MIDDLE_CLICK = 2 - SECOND_CLICK = 3 - SCROLL_UP = 4 - SCROLL_DOWN = 5 + PRIMARY = 1 + MIDDLE = 2 + SECONDARY = 3 + SCROLL_UP = 4 + SCROLL_DOWN = 5 end module Color @@ -161,17 +79,8 @@ fs.tagrules = <<EOF /.*/ -> 1 EOF - # Events - event :Start do |arg| - exit if arg == 'wmiirc' - end - - event :Key do |*args| - shortcut(*args) - end - event :CreateTag do |tag| bar = fs.lbar[tag] bar.create @@ -200,16 +109,16 @@ EOF event :LeftBarClick do |button, viewId| case button.to_i - when Mouse::FIRST_CLICK + when Mouse::PRIMARY focus_view viewId - when Mouse::MIDDLE_CLICK + when Mouse::MIDDLE # add the grouping onto the clicked view grouped_clients.each do |c| c.tag viewId end - when Mouse::SECOND_CLICK + when Mouse::SECONDARY # remove the grouping from the clicked view grouped_clients.each do |c| c.untag viewId @@ -219,7 +128,7 @@ EOF event :ClientClick do |clientId, button| case button.to_i - when Mouse::SECOND_CLICK + when Mouse::SECONDARY # toggle the clicked client's grouping Client.toggle_grouping clientId end @@ -265,146 +174,146 @@ EOF end -# Shortcuts +# Key bindings # focusing / showing # focus client at left - shortcut Key::FOCUS + Key::LEFT do + key Key::FOCUS + Key::LEFT do current_view.ctl = 'select left' end # focus client at right - shortcut Key::FOCUS + Key::RIGHT do + key Key::FOCUS + Key::RIGHT do current_view.ctl = 'select right' end # focus client below - shortcut Key::FOCUS + Key::DOWN do + key Key::FOCUS + Key::DOWN do current_view.ctl = 'select down' end # focus client above - shortcut Key::FOCUS + Key::UP do + key Key::FOCUS + Key::UP do current_view.ctl = 'select up' end # toggle focus between floating area and the columns - shortcut Key::FOCUS + 'space' do + key Key::FOCUS + 'space' do current_view.ctl = 'select toggle' end # apply equal-spacing layout to current column - shortcut Key::ARRANGE + 'w' do + key Key::ARRANGE + 'w' do current_area.layout = :default end # apply equal-spacing layout to all columns - shortcut Key::ARRANGE + 'Shift-w' do + key Key::ARRANGE + 'Shift-w' do current_view.columns.each do |a| a.layout = :default end end # apply stacked layout to currently focused column - shortcut Key::ARRANGE + 'v' do + key Key::ARRANGE + 'v' do current_area.layout = :stack end # apply stacked layout to all columns in current view - shortcut Key::ARRANGE + 'Shift-v' do + key Key::ARRANGE + 'Shift-v' do current_view.columns.each do |a| a.layout = :stack end end # apply maximized layout to currently focused column - shortcut Key::ARRANGE + 'm' do + key Key::ARRANGE + 'm' do current_area.layout = :max end # apply maximized layout to all columns in current view - shortcut Key::ARRANGE + 'Shift-m' do + key Key::ARRANGE + 'Shift-m' do current_view.columns.each do |a| a.layout = :max end end # focus the previous view - shortcut Key::FOCUS + 'comma' do + key Key::FOCUS + 'comma' do prev_view.focus end # focus the next view - shortcut Key::FOCUS + 'period' do + key Key::FOCUS + 'period' do next_view.focus end # sending / moving - shortcut Key::SEND + Key::LEFT do + key Key::SEND + Key::LEFT do grouped_clients.each do |c| c.send :left end end - shortcut Key::SEND + Key::RIGHT do + key Key::SEND + Key::RIGHT do grouped_clients.each do |c| c.send :right end end - shortcut Key::SEND + Key::DOWN do + key Key::SEND + Key::DOWN do grouped_clients.each do |c| c.send :down end end - shortcut Key::SEND + Key::UP do + key Key::SEND + Key::UP do grouped_clients.each do |c| c.send :up end end # send all grouped clients from managed to floating area (or vice versa) - shortcut Key::SEND + 'space' do + key Key::SEND + 'space' do grouped_clients.each do |c| c.send :toggle end end # close all grouped clients - shortcut Key::SEND + 'Delete' do + key Key::SEND + 'Delete' do grouped_clients.each do |c| c.ctl = 'kill' end end # swap the currently focused client with the one to its left - shortcut Key::SWAP + Key::LEFT do + key Key::SWAP + Key::LEFT do current_client.swap :left end # swap the currently focused client with the one to its right - shortcut Key::SWAP + Key::RIGHT do + key Key::SWAP + Key::RIGHT do current_client.swap :right end # swap the currently focused client with the one below it - shortcut Key::SWAP + Key::DOWN do + key Key::SWAP + Key::DOWN do current_client.swap :down end # swap the currently focused client with the one above it - shortcut Key::SWAP + Key::UP do + key Key::SWAP + Key::UP do current_client.swap :up end # Changes the tag (according to a menu choice) of each grouped client and # returns the chosen tag. The +tag -tag idea is from Jonas Pfenniger: # <http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby> - shortcut Key::SEND + 't' do + key Key::SEND + 't' do choices = tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten if target = show_menu(choices, 'tag as:') @@ -429,7 +338,7 @@ EOF # zooming / sizing # Sends grouped clients to temporary view. - shortcut Key::PREFIX + 'b' do + key Key::PREFIX + 'b' do src = current_tag dst = src + '~' + src.object_id.abs.to_s @@ -443,7 +352,7 @@ EOF end # Sends grouped clients back to their original view. - shortcut Key::PREFIX + 'Shift-b' do + key Key::PREFIX + 'Shift-b' do src = current_tag if src =~ /~\d+$/ @@ -464,52 +373,52 @@ EOF # client grouping # include/exclude the currently focused client from the grouping - shortcut Key::GROUP + 'g' do + key Key::GROUP + 'g' do current_client.toggle_grouping end # include all clients in the currently focused view in the grouping - shortcut Key::GROUP + 'v' do + key Key::GROUP + 'v' do current_view.group end # exclude all clients in the currently focused view from the grouping - shortcut Key::GROUP + 'Shift-v' do + key Key::GROUP + 'Shift-v' do current_view.ungroup end # include all clients in the currently focused column in the grouping - shortcut Key::GROUP + 'c' do + key Key::GROUP + 'c' do current_area.group end # exclude all clients in the currently focused column from the grouping - shortcut Key::GROUP + 'Shift-c' do + key Key::GROUP + 'Shift-c' do current_area.ungroup end # invert the grouping in the currently focused view - shortcut Key::GROUP + 'i' do + key Key::GROUP + 'i' do current_view.toggle_grouping end # exclude all clients everywhere from the grouping - shortcut Key::GROUP + 'n' do + key Key::GROUP + 'n' do ungroup_all end # visual arrangement - shortcut Key::ARRANGE + 't' do + key Key::ARRANGE + 't' do current_view.arrange_as_larswm end - shortcut Key::ARRANGE + 'g' do + key Key::ARRANGE + 'g' do current_view.arrange_in_grid end - shortcut Key::ARRANGE + 'd' do + key Key::ARRANGE + 'd' do current_view.arrange_in_diamond end @@ -517,7 +426,7 @@ EOF # interactive menu # launch an internal action by choosing from a menu - shortcut Key::MENU + 'i' do + key Key::MENU + 'i' do if choice = show_menu(@actionMenu + ACTIONS.keys, 'run action:') unless action choice.to_sym system choice << '&' @@ -526,21 +435,21 @@ EOF end # launch an external program by choosing from a menu - shortcut Key::MENU + 'e' do + key Key::MENU + 'e' do if choice = show_menu(@programMenu, 'run program:') system choice << '&' end end # focus any view by choosing from a menu - shortcut Key::MENU + 'u' do + key Key::MENU + 'u' do if choice = show_menu(tags, 'show view:') focus_view choice end end # focus any client by choosing from a menu - shortcut Key::MENU + 'a' do + key Key::MENU + 'a' do choices = [] clients.each_with_index do |c, i| choices << "%d. [%s] %s" % [i, c[:tags].read, c[:props].read.downcase] @@ -555,15 +464,15 @@ EOF # external programs - shortcut Key::EXECUTE + 'x' do + key Key::EXECUTE + 'x' do system 'gnome-terminal &' end - shortcut Key::EXECUTE + 'k' do + key Key::EXECUTE + 'k' do system 'firefox &' end - shortcut Key::EXECUTE + 'j' do + key Key::EXECUTE + 'j' do system 'nautilus --no-desktop &' end @@ -573,7 +482,7 @@ EOF DETACHED_TAG = '|' # Detach the current grouping from the current view. - shortcut Key::PREFIX + 'd' do + key Key::PREFIX + 'd' do grouped_clients.each do |c| c.with_tags do delete current_tag @@ -583,7 +492,7 @@ EOF end # Attach the most recently detached client onto the current view. - shortcut Key::PREFIX + 'Shift-d' do + key Key::PREFIX + 'Shift-d' do v = View.new DETACHED_TAG if v.exist? and c = v.clients.last @@ -599,19 +508,19 @@ EOF 10.times do |i| # focus the {i}'th view - shortcut Key::FOCUS + i.to_s do + key Key::FOCUS + i.to_s do focus_view tags[i - 1] || i end # send current grouping to {i}'th view - shortcut Key::SEND, i.to_s do + key Key::SEND + i.to_s do grouped_clients.each do |c| c.tags = tags[i - 1] || i end end # apply grid layout with {i} clients per column - shortcut Key::ARRANGE, i.to_s do + key Key::ARRANGE + i.to_s do current_view.arrange_in_grid i end end @@ -621,7 +530,7 @@ EOF # focus the view whose name begins with an alphabet key ('a'..'z').each do |k| - shortcut Key::VIEW + k do + key Key::VIEW + k do if t = tags.grep(/^#{k}/i).first focus_view t end @@ -629,38 +538,7 @@ EOF end -################################################################################ -# START UP -################################################################################ - -system "xsetroot -solid #{Color::BACKGROUND.inspect} &" - # Misc Setup +system "xsetroot -solid #{Color::BACKGROUND.inspect} &" action :status action :rehash - -# Tag Bar Setup -fs.lbar.clear - -tags.each do |tag| - color = (tag == current_tag) ? Color::FOCUSED : Color::NORMAL - - bar = fs.lbar[tag] - bar.create - bar.write "#{color} #{tag}" -end - -# Keygrab Setup -fs.keys = SHORTCUTS.keys.join("\n") - -# Event Loop -fs.event.open do |bus| - loop do - bus.read.split("\n").each do |event| - type, parms = event.split(' ', 2) - - args = parms.split(' ') rescue [] - event type.to_sym, *args - end - end -end