space 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,10 +6,6 @@ module Space
6
6
  autoload :App, 'space/app'
7
7
  autoload :Config, 'space/config'
8
8
  autoload :Events, 'space/events'
9
- autoload :Helpers, 'space/helpers'
10
- autoload :Logger, 'space/logger'
11
9
  autoload :Model, 'space/model'
12
- autoload :Screen, 'space/screen'
13
10
  autoload :Source, 'space/source'
14
- autoload :Tmux, 'space/tmux'
15
11
  end
@@ -30,8 +30,13 @@ module Space
30
30
  scope.each { |repo| yield repo }
31
31
  end
32
32
 
33
+ def in_repo(repo, &block)
34
+ puts "in #{repo.path}".ansi(:bold, :green)
35
+ Dir.chdir(repo.path, &block)
36
+ end
37
+
33
38
  def system(cmd)
34
- puts cmd
39
+ puts "#{cmd.ansi(:bold, :black)}\n"
35
40
  super
36
41
  end
37
42
 
@@ -4,16 +4,13 @@ module Space
4
4
  class Action
5
5
  class Execute < Action
6
6
  def run
7
- Events.sources.registered do
8
- in_scope do |repo|
9
- Dir.chdir(repo.path) do
10
- puts "in #{repo.path}\n".ansi(:bold, :green)
11
- system(*args)
12
- puts
13
- end
7
+ in_scope do |repo|
8
+ in_repo(repo) do
9
+ system(*args)
10
+ puts
14
11
  end
15
- confirm
16
12
  end
13
+ confirm
17
14
  end
18
15
  end
19
16
 
@@ -2,23 +2,19 @@ module Space
2
2
  class Action
3
3
  class Local < Action
4
4
  def run
5
- Events.sources.registered do
6
- scope.each do |repo|
7
- system "bundle config --global local.#{repo.name} #{repo.path}"
8
- end
9
- sleep 0.2 # not perfect, but fsevent is too slow to trigger
5
+ scope.each do |repo|
6
+ system "bundle config --global local.#{repo.name} #{repo.path}"
10
7
  end
8
+ confirm
11
9
  end
12
10
  end
13
11
 
14
12
  class Remote < Action
15
13
  def run
16
- Events.sources.registered do
17
- scope.each do |repo|
18
- system "bundle config --delete local.#{repo.name}"
19
- end
20
- sleep 0.2
14
+ scope.each do |repo|
15
+ system "bundle config --delete local.#{repo.name}"
21
16
  end
17
+ confirm
22
18
  end
23
19
  end
24
20
 
@@ -17,8 +17,9 @@ module Space
17
17
  def run(line)
18
18
  scope, type = parse(line)
19
19
  action = action_for(scope, type)
20
- action.run
21
- Events.flush
20
+ Events.sources.registered do
21
+ action.run
22
+ end
22
23
  end
23
24
 
24
25
  private
@@ -4,20 +4,17 @@ require 'thread'
4
4
 
5
5
  module Space
6
6
  class App
7
- attr_reader :name, :project, :screen
7
+ attr_reader :name, :project, :views
8
8
 
9
9
  def initialize(name)
10
10
  @name = name
11
11
  @project = Model::Project.new(name)
12
- @screen = Screen.new(project)
12
+ @views = [View::Progress.new(project), View::Dashboard.new(project)]
13
13
  end
14
14
 
15
15
  def run
16
- screen.display
17
16
  project.refresh
18
17
  cli_loop
19
- # Thread.new(&method(:cli_loop))
20
- # sleep
21
18
  puts
22
19
  end
23
20
 
@@ -26,7 +23,7 @@ module Space
26
23
  def cli_loop
27
24
  loop do
28
25
  print "\e[3;0H"
29
- line = Readline.readline(prompt, true) || break
26
+ line = Readline.readline(views.first.send(:prompt), true) || break
30
27
  handle(line)
31
28
  end
32
29
  rescue Exception => e
@@ -36,9 +33,5 @@ module Space
36
33
  def handle(line)
37
34
  Action::Handler.new(project).run(line) unless line.empty?
38
35
  end
39
-
40
- def prompt
41
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
42
- end
43
36
  end
44
37
  end
@@ -17,7 +17,7 @@ module Space
17
17
  end
18
18
  end
19
19
 
20
- define :template_dir => File.expand_path('../templates', __FILE__)
20
+ define :template_dir => File.expand_path('../view/templates', __FILE__)
21
21
 
22
22
  def paths
23
23
  @paths ||= repositories.map { |path| base_dir ? "#{base_dir}/#{path}" : path }
@@ -20,12 +20,6 @@ module Space
20
20
  subscriptions << Subscription.new(observer, types)
21
21
  end
22
22
 
23
- def flush
24
- event = events.first
25
- events.clear
26
- notify(event, false) if event
27
- end
28
-
29
23
  def notify(event)
30
24
  # log event
31
25
  subscriptions.each do |subscription|
@@ -15,19 +15,21 @@ module Space
15
15
  end
16
16
  end
17
17
 
18
- def register(source)
19
- Thread.exclusive do
20
- events.notify(:start) if sources.empty?
21
- sources << source
18
+ private
19
+
20
+ def register(source)
21
+ Thread.exclusive do
22
+ events.notify(:start) if sources.empty?
23
+ sources << source
24
+ end
22
25
  end
23
- end
24
26
 
25
- def unregister(source)
26
- Thread.exclusive do
27
- sources.delete(source)
28
- events.notify(:finish) if sources.empty?
27
+ def unregister(source)
28
+ Thread.exclusive do
29
+ sources.delete(source)
30
+ events.notify(:finish) if sources.empty?
31
+ end
29
32
  end
30
- end
31
33
  end
32
34
  end
33
35
  end
@@ -2,6 +2,7 @@ module Space
2
2
  module Model
3
3
  class Project
4
4
  autoload :Bundler, 'space/model/project/bundler'
5
+ autoload :Tmux, 'space/model/project/tmux'
5
6
 
6
7
  include Events
7
8
 
@@ -0,0 +1,16 @@
1
+ # TODO make this a source?
2
+ #
3
+ module Space
4
+ module Model
5
+ class Project
6
+ module Tmux
7
+ class << self
8
+ def windows
9
+ windows = `tmux list-windows -F '#W'`.split("\n")
10
+ windows unless windows.empty?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -2,7 +2,6 @@ module Space
2
2
  module Source
3
3
  autoload :Command, 'space/source/command'
4
4
  autoload :Watch, 'space/source/watch'
5
- autoload :Watcher, 'space/source/watcher'
6
5
 
7
6
  module ClassMethods
8
7
  def commands(commands = nil)
@@ -14,7 +13,7 @@ module Space
14
13
  end
15
14
  end
16
15
 
17
- include Events, Watcher
16
+ include Events
18
17
 
19
18
  class << self
20
19
  def included(base)
@@ -22,11 +21,12 @@ module Space
22
21
  end
23
22
  end
24
23
 
25
- attr_reader :results
24
+ attr_reader :path, :results
26
25
 
27
26
  def initialize(path)
27
+ @path = path
28
28
  @results = {}
29
- super
29
+ watch
30
30
  end
31
31
 
32
32
  def commands
@@ -35,10 +35,6 @@ module Space
35
35
  end
36
36
  end
37
37
 
38
- def result(key)
39
- results[key] || ''
40
- end
41
-
42
38
  def refresh
43
39
  commands.each { |key, command| command.refresh }
44
40
  end
@@ -47,5 +43,27 @@ module Space
47
43
  results[key] = result
48
44
  notify(:update)
49
45
  end
46
+
47
+ private
48
+
49
+ def result(key)
50
+ results[key] || ''
51
+ end
52
+
53
+ def watch
54
+ watchers.map(&:run)
55
+ end
56
+
57
+ def watchers
58
+ @watchers ||= watched_paths.map do |path|
59
+ Watch.new(path) { |paths| refresh }
60
+ end
61
+ end
62
+
63
+ def watched_paths
64
+ @watched_paths ||= self.class.watch.map do |path|
65
+ path[0, 1] == '~' ? path : "#{self.path}/#{path}"
66
+ end
67
+ end
50
68
  end
51
69
  end
@@ -6,12 +6,11 @@ module Space
6
6
  LATENCY = 0.1
7
7
  NO_DEFER = FALSE
8
8
 
9
- attr_reader :path, :callback, :suspended, :fsevent
9
+ attr_reader :path, :callback, :fsevent
10
10
 
11
11
  def initialize(path, &block)
12
12
  @path = File.expand_path(path)
13
13
  @callback = block
14
- # @suspended = []
15
14
  @fsevent = FSEvent.new
16
15
  end
17
16
 
@@ -23,23 +22,16 @@ module Space
23
22
  self
24
23
  end
25
24
 
26
- # def suspended?
27
- # !suspended.empty?
28
- # end
29
-
30
- # def suspend
31
- # suspended << true
32
- # end
33
-
34
- # def unsuspend
35
- # suspended.pop
36
- # end
37
-
38
25
  private
39
26
 
40
27
  def watch
41
28
  fsevent.watch(path, file: file?, latency: LATENCY, no_defer: NO_DEFER) do |paths|
42
- unless git_dir?(paths)
29
+ # git touches the .git dir on `git status` as we use this command
30
+ # internally we need to ignore this. as no other relevant action
31
+ # only touches the .git dir, we can just skip it.
32
+ paths.reject!(&method(:git_dir?))
33
+
34
+ unless paths.empty?
43
35
  log "=> WATCH triggered: #{paths.inspect}"
44
36
  fsevent.stop
45
37
  callback.call(paths)
@@ -55,8 +47,8 @@ module Space
55
47
  File.file?(path)
56
48
  end
57
49
 
58
- def git_dir?(paths)
59
- paths.size == 1 && File.basename(paths.first) == '.git'
50
+ def git_dir?(path)
51
+ File.basename(path) == '.git'
60
52
  end
61
53
  end
62
54
  end
@@ -1,3 +1,3 @@
1
1
  module Space
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -0,0 +1,57 @@
1
+ require 'erb'
2
+
3
+ module Space
4
+ class View
5
+ autoload :Helpers, 'space/view/helpers'
6
+ autoload :Progress, 'space/view/progress'
7
+ autoload :Dashboard, 'space/view/dashboard'
8
+
9
+ include Helpers
10
+
11
+ attr_reader :project
12
+
13
+ def initialize(project)
14
+ @project = project
15
+ end
16
+
17
+ def notify(event)
18
+ send(:"on_#{event}")
19
+ end
20
+
21
+ private
22
+
23
+ def render_header
24
+ print "Project #{project.name}\n\n", :at => [0, 0]
25
+ render_prompt
26
+ move 0, 5
27
+ end
28
+
29
+ def render_prompt
30
+ print prompt, :at => [0, 3]
31
+ print "\e[0K", :at => [prompt.size + 1, 3]
32
+ end
33
+
34
+ def render_template(name, assigns)
35
+ path = "#{project.config.template_dir}/#{name}.erb"
36
+ print Template.new(path).render(assigns)
37
+ end
38
+
39
+ def clear
40
+ print "\e[2J" # clear entire screen
41
+ end
42
+
43
+ def print(string, options = {})
44
+ move(*options[:at]) if options.key?(:at)
45
+ super(string)
46
+ end
47
+
48
+ def move(x, y)
49
+ print "\e[#{y};#{x}H"
50
+ end
51
+
52
+ def prompt
53
+ "#{project.repos.scoped? ? project.repos.scope.map(&:name).join(', ') : project.name} > "
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,31 @@
1
+ module Space
2
+ class View
3
+ class Dashboard < View
4
+ def initialize(*)
5
+ Events.subscribe(self, :finish)
6
+ super
7
+ end
8
+
9
+ private
10
+
11
+ def on_finish
12
+ App.log 'RENDER dashboard'
13
+ clear
14
+ render_header
15
+ render_repos
16
+ render_prompt
17
+ end
18
+
19
+ def render_repos
20
+ project.repos.scope.self_and_deps.each do |repo|
21
+ render_repo(repo)
22
+ end
23
+ end
24
+
25
+ def render_repo(repo)
26
+ assigns = { project: project, repos: project.repos, repo: repo, git: repo.git, bundle: repo.bundle }
27
+ render_template(:repo, assigns)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ require 'ansi/core'
3
+ require 'core_ext/string/wrap'
4
+
5
+ module Space
6
+ class View
7
+ module Helpers
8
+ def project_title
9
+ "Project: #{name}".ansi(:bold)
10
+ end
11
+
12
+ def tableize(string)
13
+ string.split(' ')
14
+ project.local_repos.join(', ')
15
+ end
16
+
17
+ def repo_name
18
+ repo.name.ansi(:bold)
19
+ end
20
+
21
+ def repo_status
22
+ [git.branch, git.commit, repo_local].compact.join(', ')
23
+ end
24
+
25
+ def repo_local
26
+ 'L'.ansi(:bold, :red) if repo_local?
27
+ end
28
+
29
+ def repo_local?
30
+ project.local_repos.include?(repo.name)
31
+ end
32
+
33
+ def repo_selected?
34
+ repos.scoped? && repos.scope.include?(repo)
35
+ end
36
+
37
+ def git_status
38
+ "Git: #{format_boolean(git.clean?)}#{git_ahead if git.ahead?}"
39
+ end
40
+
41
+ def git_ahead
42
+ " #{git.ahead} commit#{'s' if git.ahead > 1} ahead".ansi(:yellow)
43
+ end
44
+
45
+ def bundle_status
46
+ "Bundle: #{format_boolean(bundle.clean?)}"
47
+ end
48
+
49
+ def bundle_info
50
+ bundle.info.ansi(:red) unless bundle.clean?
51
+ end
52
+
53
+ def bundle_deps
54
+ bundle.deps.map { |dep| "• #{dep.ref} #{format_boolean(dep.fresh?)} #{dep.name}" }.join("\n")
55
+ end
56
+
57
+ def format_boolean(value)
58
+ value ? '✔'.ansi(:green, :bold) : '⚡'.ansi(:red, :bold)
59
+ end
60
+
61
+ def i(string, width = 2)
62
+ lines = string.split("\n")
63
+ lines = lines.map { |line| line.wrap(80).split("\n") }.flatten
64
+ lines = lines.map { |line| [' ' * width, line].join }
65
+ lines.join("\n")
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,25 +1,25 @@
1
1
  module Space
2
- class Screen
2
+ class View
3
3
  class Progress < View
4
4
  def initialize(*)
5
- super
6
5
  Events.subscribe(self, :start, :update)
6
+ super
7
+ render
7
8
  end
8
9
 
9
- def notify(event)
10
- case event
11
- when :start
10
+ private
11
+
12
+ def render
12
13
  clear
13
- when :update
14
- print '.'
14
+ render_header
15
15
  end
16
- end
17
16
 
18
- private
17
+ def on_start
18
+ render
19
+ end
19
20
 
20
- def clear
21
- move 0, 5
22
- print "\e[0J" # clear from cursor down
21
+ def on_update
22
+ print '.'
23
23
  end
24
24
  end
25
25
  end
@@ -0,0 +1,33 @@
1
+ module Space
2
+ class View
3
+ class Template
4
+ class << self
5
+ def [](path)
6
+ templates[path] ||= ERB.new(File.read(path), nil, '%<>-')
7
+ end
8
+
9
+ def templates
10
+ @templates ||= {}
11
+ end
12
+ end
13
+
14
+ include Helpers
15
+
16
+ attr_reader :template
17
+
18
+ def initialize(path)
19
+ @template = Template[path]
20
+ end
21
+
22
+ def render(assigns)
23
+ assigns.each { |key, value| assign(key, value) }
24
+ template.result(binding)
25
+ end
26
+
27
+ def assign(key, value)
28
+ instance_variable_set(:"@#{key}", value)
29
+ (class << self; self; end).send(:attr_reader, key)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ y%= project_title %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: space
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -33,10 +33,10 @@ files:
33
33
  - lib/space/events/sources.rb
34
34
  - lib/space/events/subscription.rb
35
35
  - lib/space/events.rb
36
- - lib/space/helpers.rb
37
36
  - lib/space/logger.rb
38
37
  - lib/space/model/project/bundler/config.rb
39
38
  - lib/space/model/project/bundler.rb
39
+ - lib/space/model/project/tmux.rb
40
40
  - lib/space/model/project.rb
41
41
  - lib/space/model/repo/bundle.rb
42
42
  - lib/space/model/repo/dependency.rb
@@ -46,18 +46,17 @@ files:
46
46
  - lib/space/model/repos/scope.rb
47
47
  - lib/space/model/repos.rb
48
48
  - lib/space/model.rb
49
- - lib/space/screen/dashboard.rb
50
- - lib/space/screen/progress.rb
51
- - lib/space/screen/view.rb
52
- - lib/space/screen.rb
53
49
  - lib/space/source/command.rb
54
50
  - lib/space/source/watch.rb
55
- - lib/space/source/watcher.rb
56
51
  - lib/space/source.rb
57
- - lib/space/templates/header.erb
58
- - lib/space/templates/repo.erb
59
- - lib/space/tmux.rb
60
52
  - lib/space/version.rb
53
+ - lib/space/view/dashboard.rb
54
+ - lib/space/view/helpers.rb
55
+ - lib/space/view/progress.rb
56
+ - lib/space/view/template.rb
57
+ - lib/space/view/templates/header.erb
58
+ - lib/space/view/templates/repo.erb
59
+ - lib/space/view.rb
61
60
  - lib/space.rb
62
61
  - Gemfile
63
62
  - Gemfile.lock
@@ -1,68 +0,0 @@
1
- # encoding: UTF-8
2
- require 'ansi/core'
3
- require 'core_ext/string/wrap'
4
-
5
- module Space
6
- module Helpers
7
- def project_title
8
- "Project: #{name}".ansi(:bold)
9
- end
10
-
11
- def tableize(string)
12
- string.split(' ')
13
- project.local_repos.join(', ')
14
- end
15
-
16
- def repo_name
17
- repo.name.ansi(:bold)
18
- end
19
-
20
- def repo_status
21
- [git.branch, git.commit, repo_local].compact.join(', ')
22
- end
23
-
24
- def repo_local
25
- 'L'.ansi(:bold, :red) if repo_local?
26
- end
27
-
28
- def repo_local?
29
- project.local_repos.include?(repo.name)
30
- end
31
-
32
- def repo_selected?
33
- repos.scoped? && repos.scope.include?(repo)
34
- end
35
-
36
- def git_status
37
- "Git: #{format_boolean(git.clean?)}#{git_ahead if git.ahead?}"
38
- end
39
-
40
- def git_ahead
41
- " #{git.ahead} commit#{'s' if git.ahead > 1} ahead".ansi(:yellow)
42
- end
43
-
44
- def bundle_status
45
- "Bundle: #{format_boolean(bundle.clean?)}"
46
- end
47
-
48
- def bundle_info
49
- bundle.info.ansi(:red) unless bundle.clean?
50
- end
51
-
52
- def bundle_deps
53
- bundle.deps.map { |dep| "• #{dep.ref} #{format_boolean(dep.fresh?)} #{dep.name}" }.join("\n")
54
- end
55
-
56
- def format_boolean(value)
57
- value ? '✔'.ansi(:green, :bold) : '⚡'.ansi(:red, :bold)
58
- end
59
-
60
- def i(string, width = 2)
61
- lines = string.split("\n")
62
- lines = lines.map { |line| line.wrap(80).split("\n") }.flatten
63
- lines = lines.map { |line| [' ' * width, line].join }
64
- lines.join("\n")
65
- end
66
- end
67
- end
68
-
@@ -1,49 +0,0 @@
1
- module Space
2
- class Screen
3
- autoload :Progress, 'space/screen/progress'
4
- autoload :Dashboard, 'space/screen/dashboard'
5
- autoload :View, 'space/screen/view'
6
-
7
- attr_reader :project, :view
8
-
9
- def initialize(project)
10
- @project = project
11
- render_header
12
- end
13
-
14
- def display
15
- @views = [Progress.new(project), Dashboard.new(project)]
16
- end
17
-
18
- # def render
19
- # view.render
20
- # move prompt.size + 1, 3
21
- # end
22
-
23
- # def notify(event)
24
- # view.notify(event)
25
- # end
26
-
27
- private
28
-
29
- def render_header
30
- print "\e[2J" # clear entire screen
31
- move 0, 0
32
- puts "Project #{project.name}\n\n"
33
- puts prompt
34
- end
35
-
36
- def move(x, y)
37
- print "\e[#{y};#{x}H"
38
- end
39
-
40
- def prompt
41
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
42
- end
43
-
44
- # def create(screen)
45
- # self.class.const_get(screen.to_s.capitalize).new(project)
46
- # end
47
- end
48
- end
49
-
@@ -1,44 +0,0 @@
1
- module Space
2
- class Screen
3
- class Dashboard < View
4
- def initialize(*)
5
- Events.subscribe(self, :finish)
6
- super
7
- end
8
-
9
- def notify(event)
10
- render
11
- end
12
-
13
- private
14
-
15
- def render
16
- App.log 'RENDER dashboard'
17
- clear
18
- render_repos
19
- move prompt.size + 1, 3
20
- print "\e[0K"
21
- end
22
-
23
- def clear
24
- move 0, 4
25
- print "\e[J" # clear from cursor down
26
- move 0, 5
27
- end
28
-
29
- def prompt
30
- "#{project.repos.scoped? ? project.repos.scope.map { |r| r.name }.join(', ') : project.name} > "
31
- end
32
-
33
- def render_repos
34
- project.repos.scope.self_and_deps.each do |repo|
35
- render_template(:repo, assigns(repo))
36
- end
37
- end
38
-
39
- def assigns(repo)
40
- { repos: project.repos, repo: repo, git: repo.git, bundle: repo.bundle }
41
- end
42
- end
43
- end
44
- end
@@ -1,39 +0,0 @@
1
- require 'erb'
2
-
3
- module Space
4
- class Screen
5
- class View
6
- include Helpers
7
-
8
- attr_reader :project
9
-
10
- def initialize(project)
11
- @project = project
12
- end
13
-
14
- private
15
-
16
- def move(x, y)
17
- print "\e[#{y};#{x}H"
18
- end
19
-
20
- def render_template(name, assigns)
21
- assigns.each { |name, value| assign(name, value) }
22
- print template(name).result(binding)
23
- end
24
-
25
- def assign(key, value)
26
- instance_variable_set(:"@#{key}", value)
27
- (class << self; self; end).send(:attr_reader, key)
28
- end
29
-
30
- def templates
31
- @templates ||= {}
32
- end
33
-
34
- def template(name)
35
- templates[name] ||= ERB.new(File.read("#{project.config.template_dir}/#{name}.erb"), nil, '%<>-')
36
- end
37
- end
38
- end
39
- end
@@ -1,32 +0,0 @@
1
- module Space
2
- module Source
3
- module Watcher
4
- attr_reader :path
5
-
6
- def initialize(path)
7
- @path = path
8
- start
9
- end
10
-
11
- def watched_paths
12
- @watched_paths ||= self.class.watch.map do |path|
13
- path[0, 1] == '~' ? path : "#{self.path}/#{path}"
14
- end
15
- end
16
-
17
- private
18
-
19
- def start
20
- watchers.map(&:run)
21
- end
22
-
23
- def watchers
24
- @watchers ||= watched_paths.map do |path|
25
- Watch.new(path) do |paths|
26
- refresh
27
- end
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1 +0,0 @@
1
- <%= project_title %>
@@ -1,11 +0,0 @@
1
- module Space
2
- module Tmux
3
- class << self
4
- def windows
5
- windows = `tmux list-windows -F '#W'`.split("\n")
6
- windows unless windows.empty?
7
- end
8
- end
9
- end
10
- end
11
-