wmiirc-rumai

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

commit 28c53e294bca12a0b279fea0baab1ff2a5172c68
parent 8d4f02346859603a77a0899dc25a0ccef50f241c
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date:   Mon, 11 Sep 2006 23:26:48 -0700

[project @ f290e1d1a16e0c998feedd8629350c9d9cd4cd4e]

[project @ 71]
add support for starting IRB with an object context
replace #with_selection with modified Array#each... so client operations always work
rm  Wmii::State.. all wmii methods accessed directly from the module

Diffstat:
fs.rb | 2+-
rc.rb | 64++++++++++++++++++++++++++++------------------------------------
wm.rb | 159+++++++++++++++++++++++++++++++++++++++++++------------------------------------
wmiirc | 124++++++++++++++++++++++++++++++++++++++++----------------------------------------
wmiish | 52+++++++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 222 insertions(+), 179 deletions(-)

diff --git a/fs.rb b/fs.rb @@ -106,7 +106,7 @@ module Ixp # Obtains the IXP node at the given path. If aCreateIt is asserted, then the given path is created unless it already exists. def initialize aPath, aCreateIt = false - @path = aPath.squeeze('/') + @path = aPath.to_s.squeeze('/') create! if aCreateIt && !exist? end diff --git a/rc.rb b/rc.rb @@ -17,11 +17,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. =end -require 'find' require 'wm' - -include Wmii -include Wmii::State +require 'find' # Returns a list of program names available in the given paths. def find_programs *aPaths @@ -55,72 +52,67 @@ end # Focuses the client chosen from a menu. def focus_client_from_menu - choices = clients.map do |c| + choices = Wmii.clients.map do |c| format "%d. [%s] %s", c.index, c.tags, c.name.downcase end target = show_menu(choices) unless target.empty? - focus_client target.scan(/\d+/).first + Wmii.focus_client target.scan(/\d+/).first end end # Changes the tag, chosen from a menu, of each selected client. # The {+tag -tag idea}[http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby] is from Jonas Pfenniger. def change_tag_from_menu - choices = tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten + choices = Wmii.tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten target = show_menu(choices) - with_selection do |c| - c.with_tags do - case target - when /^\+/ - push $' + Wmii.selected_clients.each do |c| + case target + when /^\+/ + c.tag! $' - when /^\-/ - delete $' + when /^\-/ + c.untag! $' - else - clear - push target - end + else + c.tags = target end end end # Send selected clients to temporary view or switch back again. def toggle_temp_view - curView = current_view.name + curTag = Wmii.current_view.name - if curView =~ /~\d+$/ - with_selection do |c| + if curTag =~ /~\d+$/ + Wmii.selected_clients.each do |c| c.with_tags do - delete curView + delete curTag push $` if empty? end end - focus_view $` + Wmii.focus_view $` else - tmpView = "#{curView}~#{Time.now.to_i}" + tmpTag = "#{curTag}~#{Time.now.to_i}" - with_selection do |c| - c.with_tags do - push tmpView - end + Wmii.selected_clients.each do |c| + c.tag! tmpTag end - focus_view tmpView - current_view.grid! + Wmii.focus_view tmpTag + Wmii.current_view.grid! end end # Puts focus on an adjacent view (:left or :right). def cycle_view aTarget - tags = self.tags - curTag = current_view.name + tags = Wmii.tags + curTag = Wmii.current_view.name curIndex = tags.index(curTag) newIndex = @@ -136,7 +128,7 @@ def cycle_view aTarget end % tags.length - focus_view tags[newIndex] + Wmii.focus_view tags[newIndex] end @@ -146,16 +138,16 @@ DETACHED_TAG = 'status' # Detach the current selection. def detach_selection - selected_clients.each do |c| + Wmii.selected_clients.each do |c| c.tags = DETACHED_TAG end end # Attach the most recently detached client def attach_last_client - if a = View.new("/#{DETACHED_TAG}").areas.last + if a = Wmii::View.new("/#{DETACHED_TAG}").areas.last if c = a.clients.last - c.tags = current_view.name + c.tags = Wmii.current_view.name end end end diff --git a/wm.rb b/wm.rb @@ -19,11 +19,42 @@ require 'fs' +# Encapsulates access to the window manager. module Wmii - SELECTION_TAG = 'SEL' + ## state access + + # Returns the currently focused client. + def Wmii.current_client + Client.new("/view/sel/sel") + end + + # Returns the currently focused area. + def Wmii.current_area + Area.new("/view/sel") + end + + # Returns the currently focused view. + def Wmii.current_view + View.new("/view") + end + + # Returns the current set of tags. + def Wmii.tags + Ixp.read('/tags').split + end + + # Returns the current set of views. + def Wmii.views + tags.map {|v| View.new "/#{v}"} + end + + # Returns the current set of clients. + def Wmii.clients + Area.new("/client").clients + end # Searches for the client with the given ID and returns it. If the client is not found, *nil* is returned. The search is performed within the given places if they are specified. - def find_client aClientId, aArea = nil, aView = nil + def Wmii.find_client aClientId, aArea = nil, aView = nil aClientId = aClientId.to_i needle = Client.new("/client/#{aClientId}") @@ -32,8 +63,10 @@ module Wmii if aArea && aArea.exist? areas << aArea + elsif aView && aView.exist? areas.concat aView.areas + else needle.tags.map {|t| View.new("/#{t}")}.each do |v| areas.concat v.areas @@ -50,13 +83,16 @@ module Wmii nil end + + ## state manipulation + # Focuses the view with the given name. - def focus_view aName + def Wmii.focus_view aName View.new("/#{aName}").focus! end # Focuses the client which has the given ID. - def focus_client aClientId + def Wmii.focus_client aClientId if c = find_client(aClientId) v = (a = c.parent).parent @@ -66,82 +102,35 @@ module Wmii end end - # Encapsulates the window manager's state. - module State - # Returns the currently focused client. - def current_client - Client.new("/view/sel/sel") - end - - # Returns the currently focused area. - def current_area - Area.new("/view/sel") - end - - # Returns the currently focused view. - def current_view - View.new("/view") - end - - # Returns the current set of tags. - def tags - Ixp.read('/tags').split - end - - # Returns the current set of views. - def views - tags.map {|v| View.new "/#{v}"} - end - - # Returns the current set of clients. - def clients - Area.new("/client").clients - end - - ## Multiple client selection - - # Returns a list of all selected clients in the currently focused view. If there are no selected clients, then the currently focused client is returned in the list. - def selected_clients - list = current_view.areas.map do |a| - a.clients.select {|c| c.selected?} - end - list.flatten! + ## Multiple client selection - if list.empty? - list << current_client - end + SELECTION_TAG = 'SEL' - list + # Returns a list of all selected clients in the currently focused view. If there are no selected clients, then the currently focused client is returned in the list. + def Wmii.selected_clients + list = current_view.areas.map do |a| + a.clients.select {|c| c.selected?} end + list.flatten! - # Un-selects all selected clients so that there is nothing selected. - def select_none! - View.new("/#{SELECTION_TAG}").unselect! + if list.empty? + list << current_client end - # Invokes the given block for each #selected_clients in a way that supports destructive operations, which change the number of areas in a view. - def with_selection # :yields: client - return unless block_given? + list + end - curView = current_view + # Un-selects all selected clients so that there is nothing selected. + def Wmii.select_none! + View.new("/#{SELECTION_TAG}").unselect! + end - selected_clients.each do |c| - # resolve stale paths caused by destructive operations - unless c.exist? - c = find_client(c.basename, nil, curView) - next unless c - end - yield c - end - end - end + ## subclasses for abstraction - # Head of the window manager's hierarchy. + # Head of IXP file system hierarchy. class Root < Ixp::Node - include State - def initialize super '/' end @@ -149,8 +138,6 @@ module Wmii # A region in the window manager's hierarchy. class Node < Ixp::Node - include Wmii - def initialize aParentClass, aChildClass, *aArgs @parentClass = aParentClass @childClass = aChildClass @@ -300,7 +287,10 @@ module Wmii # Inserts the given clients at the bottom of this area. def push! *aClients - clients.last.focus! if exist? + if target = clients.last + target.focus! + end + insert! aClients end @@ -322,7 +312,10 @@ module Wmii aClients.flatten! return if aClients.empty? - clients.first.focus! if exist? + if target = clients.first + target.focus! + end + setup_for_insertion! aClients.shift clients.first.ctl = 'swap down' @@ -351,7 +344,7 @@ module Wmii maxIdx = parent.indices.last maxCol = parent[maxIdx] - aFirstClient = find_client(aFirstClient.index, maxCol) + aFirstClient = Wmii.find_client(aFirstClient.index, maxCol) # move *into* final destination if maxCol.indices.length > 1 @@ -455,3 +448,23 @@ module Wmii end end end + +class Array + alias original_each each + + def each + return unless block_given? + + original_each do |c| + if c.is_a? Wmii::Client + # resolve stale paths caused by destructive operations + unless c.exist? + c = Wmii.find_client(c.basename, nil, Wmii.current_view) + next unless c + end + end + + yield c + end + end +end diff --git a/wmiirc b/wmiirc @@ -24,37 +24,36 @@ require 'rc' ## WM STARTUP -WM = Wmii::Root.new - +FS = Wmii::Root.new PROGRAM_MENU = find_programs( ENV['PATH'].squeeze(':').split(':') ) ACTION_MENU = find_programs('~/dry/apps/wmii/etc/wmii-3', File.dirname(__FILE__)) # terminate existing wmiirc processes -sleep 1 until WM.event = "Start wmiirc\n" +sleep 1 until FS.event = "Start wmiirc\n" ## UI CONFIGURATION -ENV['WMII_FONT'] = '-misc-fixed-medium-r-normal--18-120-100-100-c-90-iso10646-1' -ENV['WMII_SELCOLORS']='#ffffff #285577 #4c7899' -ENV['WMII_NORMCOLORS']='#222222 #eeeeee #666666' +ENV['FSII_FONT'] = '-misc-fixed-medium-r-normal--18-120-100-100-c-90-iso10646-1' +ENV['FSII_SELCOLORS']='#ffffff #285577 #4c7899' +ENV['FSII_NORMCOLORS']='#222222 #eeeeee #666666' system %{xsetroot -solid '#333333'} ## WM CONFIGURATION -WM.def.border = 2 +FS.def.border = 2 -WM.def.font = ENV['WMII_FONT'] -WM.def.selcolors = ENV['WMII_SELCOLORS'] -WM.def.normcolors = ENV['WMII_NORMCOLORS'] +FS.def.font = ENV['FSII_FONT'] +FS.def.selcolors = ENV['FSII_SELCOLORS'] +FS.def.normcolors = ENV['FSII_NORMCOLORS'] -WM.def.colmode = 'default' -WM.def.colwidth = 0 +FS.def.colmode = 'default' +FS.def.colwidth = 0 -WM.def.rules = <<EOS +FS.def.rules = <<EOS /jEdit.*/ -> code /Buddy List.*/ -> chat /XChat.*/ -> chat @@ -122,80 +121,80 @@ SHORTCUTS = { # focus previous area "#{FOCUS}#{LEFT}" => lambda do - current_view.ctl = 'select prev' + Wmii.current_view.ctl = 'select prev' end, # focus next area "#{FOCUS}#{RIGHT}" => lambda do - current_view.ctl = 'select next' + Wmii.current_view.ctl = 'select next' end, # focus floating area "#{FOCUS}space" => lambda do - current_view.ctl = 'select toggle' + Wmii.current_view.ctl = 'select toggle' end, # focus previous client "#{FOCUS}#{UP}" => lambda do - current_area.ctl = 'select prev' + Wmii.current_area.ctl = 'select prev' end, # focus next client "#{FOCUS}#{DOWN}" => lambda do - current_area.ctl = 'select next' + Wmii.current_area.ctl = 'select next' end, # apply equal spacing layout to currently focused column "#{LAYOUT}w" => lambda do - current_area.mode = 'default' + Wmii.current_area.mode = 'default' end, # apply stacked layout to currently focused column "#{LAYOUT}v" => lambda do - current_area.mode = 'stack' + Wmii.current_area.mode = 'stack' end, # apply maximized layout to currently focused column "#{LAYOUT}m" => lambda do - current_area.mode = 'max' + Wmii.current_area.mode = 'max' end, # maximize the floating area's focused client "#{LAYOUT}z" => lambda do - current_view[0].sel.geom = '0 0 east south' + Wmii.current_view[0].sel.geom = '0 0 east south' end, # apply tiling layout to the currently focused view "#{LAYOUT}t" => lambda do - current_view.tile! + Wmii.current_view.tile! end, # apply gridding layout to the currently focused view "#{LAYOUT}g" => lambda do - current_view.grid! + Wmii.current_view.grid! end, # add/remove the currently focused client from the selection "#{GROUP}g" => lambda do - current_client.invert_selection! + Wmii.current_client.invert_selection! end, # add all clients in the currently focused view to the selection "#{GROUP}a" => lambda do - current_view.select! + Wmii.current_view.select! end, # invert the selection in the currently focused view "#{GROUP}i" => lambda do - current_view.invert_selection! + Wmii.current_view.invert_selection! end, # nullify the selection "#{GROUP}n" => lambda do - select_none! + Wmii.select_none! end, @@ -213,7 +212,7 @@ SHORTCUTS = { # focus any view by choosing from a menu "#{MENU}Shift-v" => lambda do - focus_view(show_menu(tags)) + Wmii.focus_view(show_menu(Wmii.tags)) end, "#{MENU}a" => lambda do @@ -235,25 +234,25 @@ SHORTCUTS = { "#{SEND}#{LEFT}" => lambda do - with_selection do |c| + Wmii.selected_clients.each do |c| c.ctl = 'sendto prev' end end, "#{SEND}#{RIGHT}" => lambda do - with_selection do |c| + Wmii.selected_clients.each do |c| c.ctl = 'sendto next' end end, "#{SEND}space" => lambda do - with_selection do |c| + Wmii.selected_clients.each do |c| c.ctl = 'sendto toggle' end end, "#{SEND}Delete" => lambda do - with_selection do |c| + Wmii.selected_clients.each do |c| c.ctl = 'kill' end end, @@ -264,8 +263,10 @@ SHORTCUTS = { # remove currently focused view from current selection's tags "#{SEND}Shift-minus" => lambda do - with_selection do |c| - c.untag! current_view.name + curTag = Wmii.current_view.name + + Wmii.selected_clients.each do |c| + c.untag! curTag end end, @@ -291,22 +292,22 @@ SHORTCUTS = { # swap the currently focused client with the one to its left "#{SWAP}#{LEFT}" => lambda do - current_client.ctl = 'swap prev' + Wmii.current_client.ctl = 'swap prev' end, # swap the currently focused client with the one to its right "#{SWAP}#{RIGHT}" => lambda do - current_client.ctl = 'swap next' + Wmii.current_client.ctl = 'swap next' end, # swap the currently focused client with the one below it "#{SWAP}#{DOWN}" => lambda do - current_client.ctl = 'swap down' + Wmii.current_client.ctl = 'swap down' end, # swap the currently focused client with the one above it "#{SWAP}#{UP}" => lambda do - current_client.ctl = 'swap up' + Wmii.current_client.ctl = 'swap up' end, } @@ -315,42 +316,42 @@ SHORTCUTS = { # focus _i_th view SHORTCUTS["#{FOCUS}#{i}"] = lambda do - focus_view(tags[k] || i) + Wmii.focus_view Wmii.tags[k] || i end # send selection to _i_th view SHORTCUTS["#{SEND}#{i}"] = lambda do - with_selection do |c| - c.tags = (tags[k] || i) + Wmii.selected_clients.each do |c| + c.tags = Wmii.tags[k] || i end end # send selection to _i_th area SHORTCUTS["#{SEND}Shift-#{i}"] = lambda do - dst = current_view[i] + dstCol = Wmii.current_view[i] - with_selection do |c| - dst.insert! c + Wmii.selected_clients.each do |c| + dstCol.insert! c end end # apply grid layout with _i_ clients per column SHORTCUTS["#{LAYOUT}#{i}"] = lambda do - current_view.grid! i + Wmii.current_view.grid! i end # add _i_th view to current selection's tags SHORTCUTS["#{SEND}equal,#{i}"] = SHORTCUTS["#{SEND}Shift-equal,#{i}"] = lambda do - with_selection do |c| - c.tag! tags[k] || i + Wmii.selected_clients.each do |c| + c.tag! Wmii.tags[k] || i end end # remove _i_th view from current selection's tags SHORTCUTS["#{SEND}minus,#{i}"] = lambda do - with_selection do |c| - c.untag! tags[k] || i + Wmii.selected_clients.each do |c| + c.untag! Wmii.tags[k] || i end end end @@ -358,31 +359,31 @@ end # jump to view whose name begins with the pressed key ('a'..'z').each do |char| SHORTCUTS["#{MENU}v,#{char}"] = lambda do - choices = self.tags - choices.delete current_view.name + choices = Wmii.tags + choices.delete Wmii.current_view.name if view = choices.select {|t| t =~ /^#{char}/i}.first - focus_view view + Wmii.focus_view view end end end -WM.def.grabmod = MODKEY -WM.def.keys = SHORTCUTS.keys.join("\n") +FS.def.grabmod = MODKEY +FS.def.keys = SHORTCUTS.keys.join("\n") ## STATUS BAR Thread.new do - status = Ixp::Node.new("/bar/status", true) - status.colors = ENV['WMII_NORMCOLORS'] + sb = Ixp::Node.new('/bar/status', true) + sb.colors = ENV['FSII_NORMCOLORS'] loop do cpuLoad = `uptime`.scan(/\d+\.\d+/).join(' ') diskSpace = `df -h ~`.split[-3..-1].join(' ') 5.times do - status.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}" + sb.data = "#{Time.now.to_s} | #{cpuLoad} | #{diskSpace}" sleep 1 end end @@ -405,17 +406,17 @@ begin case mouseBtn.to_i when PRIMARY - focus_view viewId + Wmii.focus_view viewId when MIDDLE # add view to selection's tags - with_selection do |c| + Wmii.selected_clients.each do |c| c.tag! viewId end when SECONDARY # remove view from selection's tags - with_selection do |c| + Wmii.selected_clients.each do |c| c.untag! viewId end end @@ -425,7 +426,6 @@ begin case mouseBtn.to_i when MIDDLE, SECONDARY - # add/remove client from selection Wmii::Client.new("/client/#{clientId}").invert_selection! end diff --git a/wmiish b/wmiish @@ -1,7 +1,9 @@ #!/usr/bin/ruby # This is an interactive Ruby shell for wmii. # - Press the TAB key for command completion. + =begin + Copyright 2004 Joel VanderWerf Copyright 2006 Suraj N. Kurapati This program is free software; you can redistribute it and/or @@ -20,15 +22,51 @@ =end -require 'rdoc/usage' -RDoc::usage_no_exit +## This code was adapted from ruby-talk:99201. +require 'irb' +require 'irb/completion' -$:.unshift File.dirname(__FILE__) -require 'rc' +module IRB + # Starts IRB within the context of the given object. + def IRB.start_session aContextObj + IRB.setup nil unless $irb + ws = WorkSpace.new(aContextObj) -require 'irb' -require 'irb/completion' + $irb = if @CONF[:SCRIPT] # normally, set by parse_opts + Irb.new ws, @CONF[:SCRIPT] + else + Irb.new ws + end + + @CONF[:IRB_RC].call($irb.context) if @CONF[:IRB_RC] + @CONF[:MAIN_CONTEXT] = $irb.context + + trap 'INT' do + $irb.signal_handle + end + + custom_configuration if defined? IRB.custom_configuration + + catch :IRB_EXIT do + $irb.eval_input + end + end +end + +class Object + include IRB::ExtendCommandBundle # so that Marshal.dump works +end + + +if __FILE__ == $0 + # show usage info + require 'rdoc/usage' + RDoc::usage_no_exit + + $:.unshift File.dirname(__FILE__) + require 'rc' -IRB.start __FILE__ + IRB.start_session Wmii +end