소스 검색

Added the i3manager

Samuel W. Flint 8 년 전
부모
커밋
e45e8f87b0
1개의 변경된 파일224개의 추가작업 그리고 0개의 파일을 삭제
  1. 224 0
      i3man

+ 224 - 0
i3man

@@ -0,0 +1,224 @@
+#!/usr/bin/ruby
+require 'optparse'
+
+Workspace = Struct.new( "Workspace", :number, :name, :visible )
+#$max_ws = 20
+$max_ws = 500
+$min_ws = 0
+
+# External i3 calls
+def i3_switch_to_workspace( workspace_number )
+    command = 'i3-msg \'workspace number ' + workspace_number.to_s + '\''
+    puts command
+    %x{ #{command} }
+end
+
+def i3_move_window_to_workspace( workspace_number )
+    command = 'i3-msg \'move to workspace number ' + workspace_number.to_s + '\''
+    puts command
+    %x{ #{command} }
+end
+
+def get_workspaces( )
+    workspaces = %x{ i3-msg -t get_workspaces }
+    m = workspaces.scan( /{"num":\d+,"name":"\w*","visible":\w*,/ )
+
+    spaces = [ ]
+    m.each do | s |
+        # Clean up the output of i3-msg
+        # Could totally do this with a JSON parser,
+        # but I don't want the additional deps
+        s[ "{\"num\":" ] = ""
+        s[ "\"name\":" ] = ""
+        s[ "\"visible\":" ] = ""
+        s = s.split( "," )
+        s[ 1 ][ "\"" ] = ""
+        s[ 1 ][ "\"" ] = ""
+
+        # Translate from string to bool
+        if( s[ 2 ] == "true" )
+            s[ 2 ] = true
+        elsif( s[ 2 ] == "false" )
+            s[ 2 ] = false
+        end
+
+        # Translate from string to int
+        s[ 0 ] = s[ 0 ].to_i
+
+        # Add to the list of available workspaces
+        spaces.push( Workspace.new( s[ 0 ], s[ 1 ], s[ 2 ] ) )
+    end
+    return spaces
+end
+
+
+def get_next_largest_workspace( )
+    workspaces = get_workspaces( )
+    current = get_current_workspace_num( )
+    flag = 0
+    workspaces.each do | w |
+        if( flag == 1 )
+            return w.number
+        elsif( w.number == current )
+                flag = 1
+        end
+    end
+    # This is the largest workspace
+    return -1
+end
+
+def get_prev_largest_workspace( )
+    workspaces = get_workspaces( )
+    current = get_current_workspace_num( )
+    flag = 0
+    workspaces.each do | w |
+        if( w.number == current )
+            return flag
+        end
+        flag = w.number
+    end
+    # This is the smallest workspace
+    return -1
+end
+
+
+def get_current_workspace_num( )
+    workspaces = get_workspaces( )
+    current = -1
+    workspaces.each do | w |
+        if( w.visible == true )
+            current = w.number
+            break
+        end
+    end
+    return current
+end
+
+
+def workspace_exists( ws )
+    workspaces = get_workspaces( )
+    workspaces.each do | w |
+        if( ws == w.number )
+            return true
+        end
+    end
+    return false
+end
+
+
+# Generate a new workspace and switch to it
+# If that workspace already exists, make a new one right after it
+def gen_next_free_workspace( )
+    workspaces = get_workspaces( )
+    # If this is the only workspace, we want to maximize the distance
+    # this one and the next. This workspace now is the root of switching
+    new_ws = 0
+    if( workspaces.length( ) == 1 &&  get_current_workspace_num( ) == $max_ws )
+        new_ws = 0
+    else
+        next_largest = get_next_largest_workspace( )
+        if( next_largest == -1 )
+            next_largest = $max_ws
+        end
+        if( get_current_workspace_num( ) == ( next_largest - 1 ) )
+            return
+        end
+        dist_to_half = ( next_largest - get_current_workspace_num( ) ) / 2
+        new_ws = get_current_workspace_num( ) + dist_to_half
+
+        # Prevent deadlock
+        dl_flag = -1
+        while workspace_exists( new_ws ) or new_ws == get_current_workspace_num( )
+            if( dl_flag == new_ws )
+                break
+            end
+            dl_flag = new_ws
+            if( new_ws + 1 < next_largest )
+                new_ws = new_ws + 1
+            end
+        end
+    end
+    return new_ws
+end
+
+
+# Generate a new workspace and switch to it
+# If that workspace already exists, make a new one right after it
+def gen_prev_free_workspace( )
+    workspaces = get_workspaces( )
+    # If this is the only workspace, we want to maximize the distance
+    # this one and the next. This workspace now is the root of switching
+    new_ws = 0
+    if( workspaces.length( ) == 1 && get_current_workspace_num( ) == 0 )
+           new_ws = $max_ws
+    elsif
+        prev_largest = get_prev_largest_workspace( )
+        if( prev_largest == -1 )
+            prev_largest = 0
+        end
+        if( get_current_workspace_num( ) == ( prev_largest + 1 ) )
+            return
+        end
+        dist_to_half = ( get_current_workspace_num( ) - prev_largest ) / 2
+        new_ws = get_current_workspace_num( ) - dist_to_half
+        while workspace_exists( new_ws )
+
+            if( new_ws - 1 > prev_largest )
+                new_ws = new_ws - 1
+            end
+        end
+    end
+    return new_ws
+end
+
+
+options = {}
+optparse = OptionParser.new do|opts|
+    options[ :pull ] = false
+    opts.on( '-p', '--pull', 'Pull the window with you when you shift workspaces' )  do
+        options[ :pull ] = true
+    end
+
+    options[ :relative ] = false
+    opts.on( '-r', '--relative', 'Don\'t create a new workspace, only work with ones that exist' )  do
+        options[ :relative ] = true
+    end
+
+    options[ :direction ] = nil
+    opts.on( '-d', '--direction ( next|prev)', 'Move in direction specified' )  do |direction|
+        options[ :direction ] = direction
+    end
+end
+optparse.parse!
+
+
+if( options[ :direction ] == 'prev' )
+    if( options[ :relative ] )
+        if( options[ :pull ] )
+            %x{ i3-msg 'move to workspace prev' }
+        end
+        %x{ i3-msg 'workspace prev' }
+    else
+        prev_ws = gen_prev_free_workspace( )
+        if( options[ :pull ] )
+            i3_move_window_to_workspace( prev_ws )
+        end
+        i3_switch_to_workspace( prev_ws )
+    end
+elsif( options[ :direction ] == 'next' )
+    if( options[ :relative ] )
+        if( options[ :pull ] )
+            %x{ i3-msg 'move to workspace next' }
+        end
+        %x{ i3-msg 'workspace next' }
+    else
+        next_ws = gen_next_free_workspace
+        if( options[ :pull ] )
+            i3_move_window_to_workspace( next_ws )
+        end
+        i3_switch_to_workspace( next_ws )
+    end
+
+else
+    puts "Invalid direction"
+end