wmiirc-rumai

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

commit 7546eccf050e4b0ff311b542e108c4f18098b209
parent e99e9a6e3635b7eb1b0a6ca7f9d4600bbc5ac957
Author: Suraj N. Kurapati <sunaku@gmail.com>
Date:   Wed, 20 Sep 2006 20:50:09 -0700

[project @ bf86df1262574c8e44b5beaefdb21048c8acccca]

[project @ 115]
moved file test methods from Ixp into Ruby-IXP
changed Ixp::Node's method_missing behavior: nodes are only dereferenced when suffix is !
made show_menu() return nil if nothing chosen... this simplifies handling of result

Diffstat:
fs.rb | 110++++++++++++++++++++++++++-----------------------------------------------------
rc.rb | 36+++++++++++++++++-------------------
wm.rb | 113+++++++++++++++++++++++++++++++++++++++----------------------------------------
wmiirc-config.rb | 22++++++++++++----------
4 files changed, 121 insertions(+), 160 deletions(-)

diff --git a/fs.rb b/fs.rb @@ -23,143 +23,105 @@ require 'ixp' # Encapsulates access to the IXP file system. module Ixp - @@ixp = IXP::Client.new unless defined? @@ixp - - # Creates a file at the given path. - def self.create aPath - @@ixp.create aPath - end - - # Deletes the given path. - def self.remove aPath - @@ixp.remove aPath - end - - # Writes the given content to the given path. - def self.write aPath, aContent - open(aPath) do |f| - f.write aContent.to_s - end - end - - # Reads from the given path and returns the content. If the path is a directory, then the names of all files in that directory are returned. - def self.read aPath - open(aPath) do |f| - if f.is_a? IXP::Directory - names = [] - - while i = f.next - names << i.name - end - - names - - else # read file contents - f.read - end - end - end - - # Tests if the given path is a file. - def self.file? aPath - open(aPath) {|f| f.instance_of? IXP::File} rescue false - end - - # Tests if the given path is a directory. - def self.directory? aPath - open(aPath) {|f| f.instance_of? IXP::Directory} rescue false - end - - # Tests if the given path exists. - def self.exist? aPath - open(aPath) {true} rescue false - end - - # Opens the given path for reading and writing and passes it to the given block. - def self.open aPath, &aBlock # :yields: IO - @@ixp.open aPath, &aBlock - end + Client = IXP::Client.new # An entry in the IXP file system. class Node attr_reader :path - # Obtains the IXP node at the given path. If aCreateIt is asserted, then the given path is created unless it already exists. + # Obtains the IXP node at the given path. Unless it already exists, the given path is created when aCreateIt is asserted. def initialize aPath, aCreateIt = false @path = aPath.to_s.squeeze('/') create! if aCreateIt && !exist? end # Open this node for IO operation. - def open &aBlock # :yields: IO - Ixp.open @path, &aBlock + def open *aArgs, &aBlock # :yields: IO + Client.open @path, *aArgs, &aBlock end # Creates this node. def create! - Ixp.create @path + Client.create @path end # Deletes this node. def remove! - Ixp.remove @path + Client.remove @path end # Writes the given content to this node. def write! aContent - Ixp.write @path, aContent + Client.write @path, aContent end - # Returns the contents of this node or the names of all sub-nodes if this is a directory. + # Returns the contents of this node or the names of all entries if this is a directory. def read - Ixp.read @path + cont = Client.read(@path) + + if cont.respond_to? :to_ary + cont.map {|stat| stat.name} + else + cont + end end # Tests if this node is a file. def file? - Ixp.file? @path + Client.file? @path end # Tests if this node is a directory. def directory? - Ixp.directory? @path + Client.directory? @path end # Tests if this node exists in the file system. def exist? - Ixp.exist? @path + Client.exist? @path end + # Returns the basename of this file's path. def basename File.basename @path end + # Returns the dirname of this file's path. def dirname File.dirname @path end - # Accesses the given sub-path. When aDeref is asserted, then the contents of the sub-path are returned if it is a file. - def [] aSubPath, aDeref = true - child = Ixp::Node.new("#{@path}/#{aSubPath}") + # Accesses the given sub-path and dereferences it (reads its contents) if specified. + def [] aSubPath, aDeref = false + child = Node.new("#{@path}/#{aSubPath}") - if aDeref && child.file? + if aDeref child.read else child end end - # Writes to the given sub-path. + # Writes the given content to the given sub-path. def []= aSubPath, aContent - Ixp::Node.new("#{@path}/#{aSubPath}").write! aContent + self[aSubPath].write! aContent end - # Provides easy access to sub-nodes. + # Provides access to sub-nodes through method calls. + # + # :call-seq: + # node.child = value -> value + # node.child -> Node + # node.child! -> child.read + # def method_missing aMeth, *aArgs case aMeth.to_s when /=$/ self[$`] = *aArgs + when /!$/ + self[$`, true] + else self[aMeth] end diff --git a/rc.rb b/rc.rb @@ -32,33 +32,32 @@ def find_programs *aPaths end end - list.uniq.sort + list.uniq! + list.sort! + list end -# Shows a menu with the given items and returns the chosen item. If nothing was chosen, an empty string is returned. +# Shows a menu with the given items and returns the chosen item. If nothing was chosen, *nil* is returned. def show_menu *aChoices - aChoices.flatten! - output = nil - IO.popen('wmiimenu', 'r+') do |menu| - menu.write aChoices.join("\n") + menu.puts aChoices menu.close_write - output = menu.read + if (choice = menu.read).empty? + nil + else + choice + end end - - output end # Focuses the client chosen from a menu. def focus_client_from_menu choices = Wmii.clients.map do |c| - format "%d. [%s] %s", c.index, c.tags.join(' '), c.name.downcase + format "%d. [%s] %s", c.index!, c.tags!, c.name!.downcase end - target = show_menu(choices) - - unless target.empty? + if target = show_menu(choices) Wmii.focus_client target.scan(/\d+/).first end end @@ -67,9 +66,8 @@ end # 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 = Wmii.tags.map {|t| [t, "+#{t}", "-#{t}"]}.flatten - target = show_menu(choices) - unless target.empty? + if target = show_menu(choices) Wmii.selected_clients.each do |c| case target when /^\+/ @@ -89,7 +87,7 @@ end # Send selected clients to temporary view or switch back again. def toggle_temp_view - curTag = Wmii.current_view.name + curTag = Wmii.current_view.name! if curTag =~ /~\d+$/ Wmii.selected_clients.each do |c| @@ -116,7 +114,7 @@ end # Puts focus on an adjacent view (:left or :right). def cycle_view aTarget tags = Wmii.tags - curTag = Wmii.current_view.name + curTag = Wmii.current_view.name! curIndex = tags.index(curTag) newIndex = @@ -138,12 +136,12 @@ end # Toggles maximization of the currently focused client. def toggle_maximize src = Wmii.current_client - srcId = src.index + srcId = src.index! src.ctl = 'sendto toggle' dst = Wmii.current_view[0].sel - if dst.index == srcId + if dst.index! == srcId dst.geom = '0 0 east south' end end diff --git a/wm.rb b/wm.rb @@ -45,7 +45,7 @@ module Wmii # Returns the current set of tags. def Wmii.tags - Ixp.read('/tags').split + Ixp::Client.read('/tags').split end # Returns the current set of views. @@ -74,21 +74,21 @@ module Wmii needle = Wmii.get_client(aClientId) if needle.exist? - areas = [] + haystack = [] if aArea && aArea.exist? - areas << aArea + haystack << aArea elsif aView && aView.exist? - areas.concat aView.areas + haystack.concat aView.areas else needle.tags.map {|t| get_view t}.each do |v| - areas.concat v.areas + haystack.concat v.areas end end - areas.each do |a| + haystack.each do |a| if a.indices.detect {|i| i == aClientId} return a[aClientId] end @@ -233,14 +233,11 @@ module Wmii super Area, Ixp::Node, :select, *aArgs end - undef index # it prevents access to ./index file - - TAG_DELIMITER = "+" # Returns the tags associated with this client. def tags - self[:tags].split(TAG_DELIMITER) + self[:tags, true].split(TAG_DELIMITER) end # Modifies the tags associated with this client. @@ -372,39 +369,41 @@ module Wmii end end + private - # Updates the path of this area for proper insertion and inserts the given client. - def setup_for_insertion! aFirstClient - raise ArgumentError, 'nonexistent client' unless aFirstClient.exist? - - dstIdx = self.index - maxIdx = parent.indices.last - - if dstIdx > maxIdx - # move *near* final destination - clientId = aFirstClient.index - aFirstClient.ctl = "sendto #{maxIdx}" - - # recalculate b/c sendto can be destructive - maxIdx = parent.indices.last - maxCol = parent[maxIdx] - - aFirstClient = Wmii.find_client(clientId, maxCol) - - # move *into* final destination - if maxCol.indices.length > 1 - aFirstClient.ctl = "sendto next" - dstIdx = maxIdx + 1 - else - dstIdx = maxIdx - end - @path = "#{dirname}/#{dstIdx}" + # Updates the path of this area for proper insertion and inserts the given client. + def setup_for_insertion! aFirstClient + raise ArgumentError, 'nonexistent client' unless aFirstClient.exist? - else - aFirstClient.ctl = "sendto #{dstIdx}" - end + dstIdx = self.index + maxIdx = parent.indices.last + + if dstIdx > maxIdx + # move *near* final destination + clientId = aFirstClient.index! + aFirstClient.ctl = "sendto #{maxIdx}" + + # recalculate b/c sendto can be destructive + maxIdx = parent.indices.last + maxCol = parent[maxIdx] + + aFirstClient = Wmii.find_client(clientId, maxCol) + + # move *into* final destination + if maxCol.indices.length > 1 + aFirstClient.ctl = "sendto next" + dstIdx = maxIdx + 1 + else + dstIdx = maxIdx + end + + @path = "#{dirname}/#{dstIdx}" + + else + aFirstClient.ctl = "sendto #{dstIdx}" end + end end class View < Node @@ -530,17 +529,19 @@ module Wmii end end + private - # Returns the number of clients in the non-floating areas of this view. - def num_grounded_clients - if ground = areas[1..-1] - ground.inject(0) do |count, area| - count + area.length - end - else - 0 + + # Returns the number of clients in the non-floating areas of this view. + def num_grounded_clients + if ground = areas[1..-1] + ground.inject(0) do |count, area| + count + area.length end + else + 0 end + end end end @@ -549,22 +550,20 @@ class Array # Supports destructive operations on each client in this array. def each - return unless block_given? - - original_each do |c| - if c.is_a? Wmii::Client + if block_given? + original_each do |c| # resolve stale paths caused by destructive operations - unless c.exist? - puts "\n trying to resolve nonexistent client: #{c.inspect}" if $DEBUG + if c.is_a?(Wmii::Client) && !c.exist? + puts "\n trying to resolve nonexistent client: #{c.path}" if $DEBUG c = Wmii.find_client(c.basename, nil, Wmii.current_view) next unless c - puts "resolution OK: #{c.inspect}" if $DEBUG - end - end + puts "resolution OK: #{c.path}" if $DEBUG + end - yield c + yield c + end end end end diff --git a/wmiirc-config.rb b/wmiirc-config.rb @@ -170,7 +170,9 @@ SHORTCUTS = { # maximize the floating area's focused client "#{LAYOUT_SEQ}z" => lambda do - Wmii.current_view[0].sel.geom = '0 0 east south' + if (client = Wmii.current_view[0].sel).exist? + client.geom = '0 0 east south' + end end, @@ -234,7 +236,7 @@ SHORTCUTS = { # focus any view by choosing from a menu "#{MENU_SEQ}u" => lambda do - unless (choice = show_menu(Wmii.tags)).empty? + if choice = show_menu(Wmii.tags) Wmii.focus_view choice end end, @@ -278,11 +280,11 @@ SHORTCUTS = { "#{SEND_SEQ}Delete" => lambda do # reverse b/c client indices are reassigned upon deletion. # ex: imagine you have these clients: [1, 2, 3] - # you delete the first client (index 1). - # now, wmii reorders the client indices: [1, 2] + # you delete the second client (id 2). + # now, wmii reorders the remaining clients [1, 3] as: [1, 2] # that is why we must go in reverse! Wmii.selected_clients.sort_by do |c| - c.index.to_i + c.index!.to_i end.reverse.each do |c| c.ctl = 'kill' end @@ -294,7 +296,7 @@ SHORTCUTS = { # remove currently focused view from current selection's tags "#{SEND_SEQ}Shift-minus" => lambda do - curTag = Wmii.current_view.name + curTag = Wmii.current_view.name! Wmii.selected_clients.each do |c| c.untag! curTag @@ -393,12 +395,12 @@ SHORTCUTS = { end # jump to view whose name begins with the pressed key -('a'..'z').each do |char| - SHORTCUTS["#{MENU_SEQ}v,#{char}"] = lambda do +('a'..'z').each do |key| + SHORTCUTS["#{MENU_SEQ}v,#{key}"] = lambda do choices = Wmii.tags - choices.delete Wmii.current_view.name + choices.delete Wmii.current_view.name! - if view = choices.select {|t| t =~ /^#{char}/i}.first + if view = choices.select {|t| t =~ /^#{key}/i}.first Wmii.focus_view view end end