fusuma-plugin-wmctrl 0.2.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f32faf629716120700464642e1d591691413d7240e1000c2774514a57402b8d
4
- data.tar.gz: 46b22611de856c05893885e04fb0e38769b7f5cda314776484cd9983fc24c38e
3
+ metadata.gz: be4879e5eb3aa9c3db5c366947afdaaf4e88c0ce883976dec7f67175fee10a0b
4
+ data.tar.gz: dda7a911dcd37e050886f9265b98a876d01558ce718817d787ecb1d13b20923b
5
5
  SHA512:
6
- metadata.gz: eb007ac0e18cc78797e3211c269c279f4da0af4f0d8c0e95129108b533d6dc6f117800efdc751cc9b5a2ad6ab4feff9a308abb11c7f0d3d6d4ef5b81634b9a30
7
- data.tar.gz: 5a2287cce23e47ed30153cc6668edce591695093c8a5323a8b0472ead69d6a9372b744be810d24ef38980d71ac5fa33300723b95cbd3a9f8c90797a628e59d2b
6
+ metadata.gz: 83cbb9dfef7b628b29e48576eaab00ff59a6573ac8fe514e9d802699dfc1469fc91ccd6fb1bdcaf59f2691d2273a02295b936ac60807192783563323eb4b67b0
7
+ data.tar.gz: 606efefee934e4681f83dda6960450fd533f577d31bc11c893f541fb9582432e886b762ae962f18ef429913d35358c3fc10fabdf9004b4c4b345374ea1bc8e07
data/README.md CHANGED
@@ -3,21 +3,38 @@
3
3
 
4
4
  Window Manager plugin for [Fusuma](https://github.com/iberianpig/fusuma)
5
5
 
6
+ * Move window or workspace instead of xdotool
7
+ * Works on Wayland(Not depends on xdotool)
8
+
6
9
  ## Installation
7
10
 
8
11
  Run the following code in your terminal.
9
12
 
10
- ### Install wmctrl
13
+ ### 1.Install wmctrl
14
+
15
+ #### For Debian Based Distros (Ubuntu, Debian, Mint, Pop!_OS)
16
+
17
+ ```
18
+ $ sudo apt install wmctrl -y
19
+ ```
20
+
21
+ #### For Arch Based Distros (Manjaro, Arch)
11
22
 
12
23
  ```
13
- $ sudo apt install wmctrl
24
+ sudo pacman -S wmctrl
14
25
  ```
15
- ### Install fusuma-plugin-wmctrl
26
+
27
+ ### 2. Install fusuma-plugin-wmctrl
16
28
 
17
29
  This plugin requires [Fusuma](https://github.com/iberianpig/fusuma#update) version 1.0 or later.
18
30
 
31
+
32
+ **Note For Arch Based Distros:** By default in Arch Linux, when running ```gem```, gems are installed per-user (into ```~/.gem/ruby/```), instead of system-wide (into ```/usr/lib/ruby/gems/```). This is considered the best way to manage gems on Arch, because otherwise they might interfere with gems installed by Pacman. (From Arch Wiki)
33
+
34
+ To install gems system-wide, see any of the methods listed on [Arch Wiki](https://wiki.archlinux.org/index.php/ruby#Installing_gems_system-wide)
35
+
19
36
  ```sh
20
- $ gem install fusuma-plugin-wmctrl
37
+ $ sudo gem install fusuma-plugin-wmctrl
21
38
  ```
22
39
 
23
40
  ## Properties
@@ -30,13 +47,53 @@ Values following are available for `workspace`.
30
47
  * `prev` is value to switch current workspace to previous workspace.
31
48
  * `next` is value to switch current workspace to next workspace.
32
49
 
33
- ### `window:` property for moving active window
50
+ ### `window:` property
34
51
  Add `window:` property in `~/.config/fusuma/config.yml`.
35
52
 
36
53
  Values following are available for `window`.
37
54
 
38
55
  * `prev` is value to move active window to previous workspace.
39
56
  * `next` is value to move active window to next workspace.
57
+ * `fullscreen` is value to toggle fullscreen
58
+ * `fullscreen: toggle` toggles the active window to fullscreen.
59
+ ```yml
60
+ window: fullscreen
61
+ # ↑ same ↓
62
+ window:
63
+ fullscreen: toggle
64
+ ```
65
+
66
+ * `fullscreen: add` changes the active window to a fullscreen.
67
+ ```yml
68
+ window:
69
+ fullscreen: add
70
+ ```
71
+
72
+ * `fullscreen: remove` restores the active window from fullscreen.
73
+ ```yml
74
+ window:
75
+ fullscreen: remove
76
+ ```
77
+ * `maximized` is value to toggle maximized
78
+ * `maximized: toggle` toggles the active window to maximized.
79
+ ```yml
80
+ window: maximized
81
+ # ↑ same ↓
82
+ window:
83
+ maximized: toggle
84
+ ```
85
+
86
+ * `maximized: add` changes the active window to a maximized.
87
+ ```yml
88
+ window:
89
+ maximized: add
90
+ ```
91
+
92
+ * `maximized: remove` restores the active window from maximized.
93
+ ```yml
94
+ window:
95
+ maximized: remove
96
+ ```
40
97
 
41
98
 
42
99
  ## Example
@@ -52,6 +109,17 @@ swipe:
52
109
  workspace: 'prev'
53
110
  ```
54
111
 
112
+ ## Configuration
113
+
114
+ The plugin allows to enable (disabled by default) circular navigation between workspaces. To enable it set the following in your config file `~/.config/fusuma/config.yml`.
115
+
116
+ ```yaml
117
+ plugin:
118
+ executors:
119
+ wmctrl_executor:
120
+ wrap-navigation: true
121
+ ```
122
+
55
123
 
56
124
  ## Contributing
57
125
 
@@ -16,25 +16,12 @@ Gem::Specification.new do |spec|
16
16
  spec.license = 'MIT'
17
17
 
18
18
  # Specify which files should be added to the gem when it is released.
19
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
- end
19
+ spec.files = Dir['{bin,lib,exe}/**/*', 'LICENSE*', 'README*', '*.gemspec']
20
+ spec.test_files = Dir['{test,spec,features}/**/*']
23
21
  spec.bindir = 'exe'
24
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
23
  spec.require_paths = ['lib']
26
24
 
27
25
  spec.required_ruby_version = '>= 2.3' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
28
- spec.add_dependency 'fusuma', '~> 1.0'
29
-
30
- spec.add_development_dependency 'bundler'
31
- spec.add_development_dependency 'github_changelog_generator', '~> 1.14'
32
- spec.add_development_dependency 'pry-byebug', '~> 3.4'
33
- spec.add_development_dependency 'pry-doc'
34
- spec.add_development_dependency 'pry-inline'
35
- spec.add_development_dependency 'rake', '~> 13.0'
36
- spec.add_development_dependency 'reek'
37
- spec.add_development_dependency 'rspec', '~> 3.0'
38
- spec.add_development_dependency 'rubocop'
39
- spec.add_development_dependency 'yard'
26
+ spec.add_dependency 'fusuma', '~> 2.0.0'
40
27
  end
@@ -1,10 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'posix/spawn'
4
+ require 'singleton'
5
+
3
6
  module Fusuma
4
7
  module Plugin
5
8
  module Executors
6
9
  # Control Window or Workspaces by executing wctrl
7
10
  class WmctrlExecutor < Executor
11
+ # executor properties on config.yml
12
+ # @return [Array<Symbol>]
13
+ def execute_keys
14
+ %i[wmctrl workspace]
15
+ end
16
+
17
+ def config_param_types
18
+ {
19
+ 'wrap-navigation': [TrueClass, FalseClass]
20
+ }
21
+ end
22
+
23
+ def initialize
24
+ super()
25
+ Workspace.configure(wrap_navigation: config_params(:'wrap-navigation'))
26
+ end
27
+
8
28
  # execute wmctrl command
9
29
  # @param event [Event]
10
30
  # @return [nil]
@@ -12,11 +32,7 @@ module Fusuma
12
32
  return if search_command(event).nil?
13
33
 
14
34
  MultiLogger.info(wmctrl: search_command(event))
15
- pid = fork do
16
- Process.daemon(true)
17
- exec(search_command(event))
18
- end
19
-
35
+ pid = POSIX::Spawn.spawn(search_command(event))
20
36
  Process.detach(pid)
21
37
  end
22
38
 
@@ -45,7 +61,7 @@ module Fusuma
45
61
  index = Config::Index.new([*event.record.index.keys, :workspace])
46
62
 
47
63
  direction = Config.search(index)
48
- return if direction.nil?
64
+ return unless direction.is_a?(String)
49
65
 
50
66
  Workspace.move_command(direction: direction)
51
67
  end
@@ -56,49 +72,112 @@ module Fusuma
56
72
  def search_window_command(event)
57
73
  index = Config::Index.new([*event.record.index.keys, :window])
58
74
 
59
- direction = Config.search(index)
60
- return if direction.nil?
61
-
62
- Window.move_command(direction: direction)
75
+ case property = Config.search(index)
76
+ when 'prev', 'next'
77
+ Window.move_command(direction: property)
78
+ when 'fullscreen'
79
+ Window.fullscreen(method: 'toggle')
80
+ when 'maximized'
81
+ Window.maximized(method: 'toggle')
82
+ when 'close'
83
+ Window.close
84
+ when Hash
85
+ if property[:fullscreen]
86
+ Window.fullscreen(method: property[:fullscreen])
87
+ elsif property[:maximized]
88
+ Window.maximized(method: property[:maximized])
89
+ end
90
+ end
63
91
  end
64
92
 
65
93
  # Manage workspace
66
94
  class Workspace
95
+ include Singleton
96
+
97
+ attr_accessor :wrap_navigation
98
+
67
99
  class << self
68
- # get workspace number
100
+ # configure properties of the workspace switcher
101
+ # @return [NilClass]
102
+ def configure(wrap_navigation:)
103
+ instance.wrap_navigation = wrap_navigation
104
+ end
105
+
106
+ # get next workspace number
69
107
  # @return [Integer]
70
- def current_workspace_num
71
- text = `wmctrl -d`.split("\n").grep(/\*/).first
72
- text.chars.first.to_i
108
+ def next_workspace_num(step:)
109
+ current_workspace_num, total_workspace_num = workspace_values
110
+
111
+ next_workspace_num = current_workspace_num + step
112
+
113
+ return next_workspace_num unless instance.wrap_navigation
114
+
115
+ if next_workspace_num.negative?
116
+ next_workspace_num = total_workspace_num - 1
117
+ elsif next_workspace_num >= total_workspace_num
118
+ next_workspace_num = 0
119
+ else
120
+ next_workspace_num
121
+ end
73
122
  end
74
123
 
75
124
  def move_command(direction:)
76
125
  workspace_num = case direction
77
126
  when 'next'
78
- current_workspace_num + 1
127
+ next_workspace_num(step: 1)
79
128
  when 'prev'
80
- current_workspace_num - 1
129
+ next_workspace_num(step: -1)
81
130
  else
82
- warn "#{direction} is invalid key"
83
- exit 1
131
+ raise "#{direction} is invalid key"
84
132
  end
85
133
  "wmctrl -s #{workspace_num}"
86
134
  end
135
+
136
+ private
137
+
138
+ # get current workspace and total workspace numbers
139
+ # @return [Integer, Integer]
140
+ def workspace_values
141
+ wmctrl_output = `wmctrl -d`.split("\n")
142
+
143
+ current_line = wmctrl_output.grep(/\*/).first
144
+ # NOTE: stderror when failed to get desktop
145
+ # `Cannot get current desktop properties. (_NET_CURRENT_DESKTOP or _WIN_WORKSPACE property)`
146
+ return [0, 1] if current_line.nil?
147
+
148
+ current_workspace_num = current_line.chars.first.to_i
149
+ total_workspace_num = wmctrl_output.length
150
+
151
+ [current_workspace_num, total_workspace_num]
152
+ end
87
153
  end
88
154
  end
89
155
 
90
156
  # Manage Window
91
157
  class Window
92
158
  class << self
159
+ # @param method [String] "toggle" or "add" or "remove"
160
+ def maximized(method:)
161
+ "wmctrl -r :ACTIVE: -b #{method},maximized_vert,maximized_horz"
162
+ end
163
+
164
+ def close
165
+ 'wmctrl -c :ACTIVE:'
166
+ end
167
+
168
+ # @param method [String] "toggle" or "add" or "remove"
169
+ def fullscreen(method:)
170
+ "wmctrl -r :ACTIVE: -b #{method},fullscreen"
171
+ end
172
+
93
173
  def move_command(direction:)
94
174
  workspace_num = case direction
95
175
  when 'next'
96
- Workspace.current_workspace_num + 1
176
+ Workspace.next_workspace_num(step: 1)
97
177
  when 'prev'
98
- Workspace.current_workspace_num - 1
178
+ Workspace.next_workspace_num(step: -1)
99
179
  else
100
- warn "#{direction} is invalid key"
101
- exit 1
180
+ raise "#{direction} is invalid key"
102
181
  end
103
182
  "wmctrl -r :ACTIVE: -t #{workspace_num} ; wmctrl -s #{workspace_num}"
104
183
  end
@@ -3,7 +3,7 @@
3
3
  module Fusuma
4
4
  module Plugin
5
5
  module Wmctrl
6
- VERSION = '0.2.0'
6
+ VERSION = '0.4.1'
7
7
  end
8
8
  end
9
9
  end
@@ -0,0 +1,476 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'fusuma/plugin/executors/executor'
6
+ require 'fusuma/plugin/events/event'
7
+ require 'fusuma/plugin/events/records/index_record'
8
+
9
+ require './lib/fusuma/plugin/executors/wmctrl_executor'
10
+
11
+ module Fusuma
12
+ module Plugin
13
+ module Executors
14
+ RSpec.describe WmctrlExecutor do
15
+ before do
16
+ index = Config::Index.new([:dummy, 1, :direction])
17
+ record = Events::Records::IndexRecord.new(index: index)
18
+ @event = Events::Event.new(tag: 'dummy_detector', record: record)
19
+ @executor = WmctrlExecutor.new
20
+
21
+ @default_workspace_num = 1
22
+ allow(WmctrlExecutor::Workspace)
23
+ .to receive(:workspace_values)
24
+ .and_return(@default_workspace_num)
25
+ end
26
+
27
+ around do |example|
28
+ ConfigHelper.load_config_yml = <<~CONFIG
29
+ dummy:
30
+ 1:
31
+ direction:
32
+ workspace: 'prev'
33
+ CONFIG
34
+
35
+ example.run
36
+
37
+ Config.custom_path = nil
38
+ end
39
+
40
+ describe '#execute' do
41
+ it 'detach' do
42
+ pid = rand(20)
43
+ allow(POSIX::Spawn)
44
+ .to receive(:spawn).with(@executor.search_command(@event))
45
+ .and_return pid
46
+
47
+ expect(Process).to receive(:detach).with(pid)
48
+
49
+ @executor.execute(@event)
50
+ end
51
+ end
52
+
53
+ describe '#executable?' do
54
+ context 'when given valid event tagged as xxxx_detector' do
55
+ it { expect(@executor.executable?(@event)).to be_truthy }
56
+ end
57
+
58
+ context 'when given INVALID event tagged as invalid_tag' do
59
+ before do
60
+ @event.tag = 'invalid_tag'
61
+ end
62
+ it { expect(@executor.executable?(@event)).to be_falsey }
63
+ end
64
+ end
65
+
66
+ describe '#search_command' do
67
+
68
+ context "when workspace: 'prev'" do
69
+ around do |example|
70
+ ConfigHelper.load_config_yml = <<~CONFIG
71
+ dummy:
72
+ 1:
73
+ direction:
74
+ workspace: 'prev'
75
+ CONFIG
76
+
77
+ example.run
78
+
79
+ Config.custom_path = nil
80
+ end
81
+
82
+ it 'should return wmctrl command' do
83
+ expect(@executor.search_command(@event))
84
+ .to match(/wmctrl -s #{@default_workspace_num - 1}/)
85
+ end
86
+ end
87
+
88
+ context "when workspace: 'next'" do
89
+ around do |example|
90
+ ConfigHelper.load_config_yml = <<~CONFIG
91
+ dummy:
92
+ 1:
93
+ direction:
94
+ workspace: 'next'
95
+ CONFIG
96
+
97
+ example.run
98
+
99
+ Config.custom_path = nil
100
+ end
101
+
102
+ it 'should return wmctrl command' do
103
+ expect(@executor.search_command(@event))
104
+ .to match(/wmctrl -s #{@default_workspace_num + 1}/)
105
+ end
106
+ end
107
+
108
+ context "when window: 'prev'" do
109
+ around do |example|
110
+ ConfigHelper.load_config_yml = <<~CONFIG
111
+ dummy:
112
+ 1:
113
+ direction:
114
+ window: 'prev'
115
+ CONFIG
116
+
117
+ example.run
118
+
119
+ Config.custom_path = nil
120
+ end
121
+
122
+ it 'should return wmctrl command' do
123
+ expect(@executor.search_command(@event))
124
+ .to match(/wmctrl -r :ACTIVE: -t #{@default_workspace_num - 1}/)
125
+ expect(@executor.search_command(@event))
126
+ .to match(/wmctrl -s #{@default_workspace_num - 1}/)
127
+ end
128
+ end
129
+
130
+ context "when window: 'next'" do
131
+ around do |example|
132
+ ConfigHelper.load_config_yml = <<~CONFIG
133
+ dummy:
134
+ 1:
135
+ direction:
136
+ window: 'next'
137
+ CONFIG
138
+
139
+ example.run
140
+
141
+ Config.custom_path = nil
142
+ end
143
+
144
+ it 'should return wmctrl command' do
145
+ expect(@executor.search_command(@event))
146
+ .to match(/wmctrl -r :ACTIVE: -t #{@default_workspace_num + 1}/)
147
+ expect(@executor.search_command(@event))
148
+ .to match(/wmctrl -s #{@default_workspace_num + 1}/)
149
+ end
150
+ end
151
+
152
+ context "when window: 'fullscreen'" do
153
+ around do |example|
154
+ ConfigHelper.load_config_yml = <<~CONFIG
155
+ dummy:
156
+ 1:
157
+ direction:
158
+ window: 'fullscreen'
159
+ CONFIG
160
+
161
+ example.run
162
+
163
+ Config.custom_path = nil
164
+ end
165
+
166
+ it 'should return wmctrl command' do
167
+ expect(@executor.search_command(@event))
168
+ .to match(/wmctrl -r :ACTIVE: -b toggle,fullscreen/)
169
+ end
170
+ end
171
+
172
+ context 'when window: [fullscreen: something]' do
173
+ context "when fullscreen: 'toggle'" do
174
+ around do |example|
175
+ ConfigHelper.load_config_yml = <<~CONFIG
176
+ dummy:
177
+ 1:
178
+ direction:
179
+ window:
180
+ fullscreen: 'toggle'
181
+ CONFIG
182
+
183
+ example.run
184
+
185
+ Config.custom_path = nil
186
+ end
187
+
188
+ it 'should return wmctrl command' do
189
+ expect(@executor.search_command(@event))
190
+ .to match(/wmctrl -r :ACTIVE: -b toggle,fullscreen/)
191
+ end
192
+ end
193
+
194
+ context "when fullscreen: 'add'" do
195
+ around do |example|
196
+ ConfigHelper.load_config_yml = <<~CONFIG
197
+ dummy:
198
+ 1:
199
+ direction:
200
+ window:
201
+ fullscreen: 'add'
202
+ CONFIG
203
+
204
+ example.run
205
+
206
+ Config.custom_path = nil
207
+ end
208
+
209
+ it 'should return wmctrl command' do
210
+ expect(@executor.search_command(@event))
211
+ .to match(/wmctrl -r :ACTIVE: -b add,fullscreen/)
212
+ end
213
+ end
214
+
215
+ context "when fullscreen: 'remove'" do
216
+ around do |example|
217
+ ConfigHelper.load_config_yml = <<~CONFIG
218
+ dummy:
219
+ 1:
220
+ direction:
221
+ window:
222
+ fullscreen: 'remove'
223
+ CONFIG
224
+
225
+ example.run
226
+
227
+ Config.custom_path = nil
228
+ end
229
+
230
+ it 'should return wmctrl command' do
231
+ expect(@executor.search_command(@event))
232
+ .to match(/wmctrl -r :ACTIVE: -b remove,fullscreen/)
233
+ end
234
+ end
235
+ end
236
+
237
+ context "when window: 'maximized'" do
238
+ around do |example|
239
+ ConfigHelper.load_config_yml = <<~CONFIG
240
+ dummy:
241
+ 1:
242
+ direction:
243
+ window: 'maximized'
244
+ CONFIG
245
+
246
+ example.run
247
+
248
+ Config.custom_path = nil
249
+ end
250
+
251
+ it 'should return wmctrl command' do
252
+ expect(@executor.search_command(@event))
253
+ .to match(/wmctrl -r :ACTIVE: -b toggle,maximized/)
254
+ end
255
+ end
256
+
257
+ context 'when window: [maximized: something]' do
258
+ context "when maximized: 'toggle'" do
259
+ around do |example|
260
+ ConfigHelper.load_config_yml = <<~CONFIG
261
+ dummy:
262
+ 1:
263
+ direction:
264
+ window:
265
+ maximized: 'toggle'
266
+ CONFIG
267
+
268
+ example.run
269
+
270
+ Config.custom_path = nil
271
+ end
272
+
273
+ it 'should return wmctrl command' do
274
+ expect(@executor.search_command(@event))
275
+ .to match(/wmctrl -r :ACTIVE: -b toggle,maximized/)
276
+ end
277
+ end
278
+
279
+ context "when maximized: 'add'" do
280
+ around do |example|
281
+ ConfigHelper.load_config_yml = <<~CONFIG
282
+ dummy:
283
+ 1:
284
+ direction:
285
+ window:
286
+ maximized: 'add'
287
+ CONFIG
288
+
289
+ example.run
290
+
291
+ Config.custom_path = nil
292
+ end
293
+
294
+ it 'should return wmctrl command' do
295
+ expect(@executor.search_command(@event))
296
+ .to match(/wmctrl -r :ACTIVE: -b add,maximized/)
297
+ end
298
+ end
299
+
300
+ context "when maximized: 'remove'" do
301
+ around do |example|
302
+ ConfigHelper.load_config_yml = <<~CONFIG
303
+ dummy:
304
+ 1:
305
+ direction:
306
+ window:
307
+ maximized: 'remove'
308
+ CONFIG
309
+
310
+ example.run
311
+
312
+ Config.custom_path = nil
313
+ end
314
+
315
+ it 'should return wmctrl command' do
316
+ expect(@executor.search_command(@event))
317
+ .to match(/wmctrl -r :ACTIVE: -b remove,maximized/)
318
+ end
319
+ end
320
+ end
321
+ context "when window: 'close'" do
322
+ around do |example|
323
+ ConfigHelper.load_config_yml = <<~CONFIG
324
+ dummy:
325
+ 1:
326
+ direction:
327
+ window: 'close'
328
+ CONFIG
329
+
330
+ example.run
331
+
332
+ Config.custom_path = nil
333
+ end
334
+
335
+ it 'should return wmctrl command' do
336
+ expect(@executor.search_command(@event))
337
+ .to match(/wmctrl -c :ACTIVE:/)
338
+ end
339
+ end
340
+
341
+ describe 'wrap_navigation: true' do
342
+
343
+ context "when workspace: 'prev' and current workspace 0" do
344
+ around do |example|
345
+ ConfigHelper.load_config_yml = <<~CONFIG
346
+ dummy:
347
+ 1:
348
+ direction:
349
+ workspace: 'prev'
350
+ plugin:
351
+ executors:
352
+ wmctrl_executor:
353
+ wrap-navigation: true
354
+ CONFIG
355
+
356
+ example.run
357
+
358
+ Config.custom_path = nil
359
+ end
360
+
361
+ it 'should return wmctrl command with an index last workspace' do
362
+ current_workspace = 0
363
+ total_workspaces = 3
364
+
365
+ allow(WmctrlExecutor::Workspace)
366
+ .to receive(:workspace_values)
367
+ .and_return([current_workspace, total_workspaces])
368
+
369
+ expect(@executor.search_command(@event))
370
+ .to match(/wmctrl -s #{total_workspaces - 1}/)
371
+ end
372
+ end
373
+
374
+ context "when workspace: 'next' and current workspace = total - 1" do
375
+ around do |example|
376
+ ConfigHelper.load_config_yml = <<~CONFIG
377
+ dummy:
378
+ 1:
379
+ direction:
380
+ workspace: 'next'
381
+ plugin:
382
+ executors:
383
+ wmctrl_executor:
384
+ wrap-navigation: true
385
+ CONFIG
386
+
387
+ example.run
388
+
389
+ Config.custom_path = nil
390
+ end
391
+
392
+ it 'should return wmctrl command with an index of first workspace' do
393
+ current_workspace = 3
394
+ total_workspaces = 4
395
+
396
+ allow(WmctrlExecutor::Workspace)
397
+ .to receive(:workspace_values)
398
+ .and_return([current_workspace, total_workspaces])
399
+
400
+ expect(@executor.search_command(@event))
401
+ .to match(/wmctrl -s 0/)
402
+ end
403
+ end
404
+
405
+ context "when window: 'prev' and current workspace has index 0" do
406
+ around do |example|
407
+ ConfigHelper.load_config_yml = <<~CONFIG
408
+ dummy:
409
+ 1:
410
+ direction:
411
+ window: 'prev'
412
+ plugin:
413
+ executors:
414
+ wmctrl_executor:
415
+ wrap-navigation: true
416
+ CONFIG
417
+
418
+ example.run
419
+
420
+ Config.custom_path = nil
421
+ end
422
+
423
+ it 'should return wmctrl command with index of last workspace' do
424
+ current_workspace = 0
425
+ total_workspaces = 5
426
+
427
+ allow(WmctrlExecutor::Workspace)
428
+ .to receive(:workspace_values)
429
+ .and_return([current_workspace, total_workspaces])
430
+
431
+ expect(@executor.search_command(@event))
432
+ .to match(/wmctrl -r :ACTIVE: -t #{total_workspaces - 1}/)
433
+ expect(@executor.search_command(@event))
434
+ .to match(/wmctrl -s #{total_workspaces - 1}/)
435
+ end
436
+ end
437
+
438
+ context "when window: 'next' and current workspace is last" do
439
+ around do |example|
440
+ ConfigHelper.load_config_yml = <<~CONFIG
441
+ dummy:
442
+ 1:
443
+ direction:
444
+ window: 'next'
445
+ plugin:
446
+ executors:
447
+ wmctrl_executor:
448
+ wrap-navigation: true
449
+ CONFIG
450
+
451
+ example.run
452
+
453
+ Config.custom_path = nil
454
+ end
455
+
456
+ it 'should return wmctrl command with index of first workspace' do
457
+ current_workspace = 4
458
+ total_workspaces = 5
459
+
460
+ allow(WmctrlExecutor::Workspace)
461
+ .to receive(:workspace_values)
462
+ .and_return([current_workspace, total_workspaces])
463
+
464
+ expect(@executor.search_command(@event))
465
+ .to match(/wmctrl -r :ACTIVE: -t 0/)
466
+ expect(@executor.search_command(@event))
467
+ .to match(/wmctrl -s 0/)
468
+ end
469
+ end
470
+
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
476
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Fusuma::Plugin::Wmctrl do
6
+ it 'has a version number' do
7
+ expect(Fusuma::Plugin::Wmctrl::VERSION).not_to be nil
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tempfile'
4
+ require 'fusuma/config.rb'
5
+
6
+ module Fusuma
7
+ module ConfigHelper
8
+ module_function
9
+
10
+ def load_config_yml=(string)
11
+ Config.custom_path = Tempfile.open do |temp_file|
12
+ temp_file.tap { |f| f.write(string) }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'helpers/config_helper.rb'
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = '.rspec_status'
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+
17
+ config.include(Fusuma::ConfigHelper)
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusuma-plugin-wmctrl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-07 00:00:00.000000000 Z
11
+ date: 2021-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fusuma
@@ -16,154 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: 2.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: github_changelog_generator
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '1.14'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '1.14'
55
- - !ruby/object:Gem::Dependency
56
- name: pry-byebug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.4'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.4'
69
- - !ruby/object:Gem::Dependency
70
- name: pry-doc
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: pry-inline
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rake
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '13.0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '13.0'
111
- - !ruby/object:Gem::Dependency
112
- name: reek
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: rspec
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3.0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3.0'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: yard
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
26
+ version: 2.0.0
167
27
  description: fusuma-plugin-wmctrl is Fusuma plugin for window manager.
168
28
  email:
169
29
  - yhkyky@gmail.com
@@ -171,23 +31,18 @@ executables: []
171
31
  extensions: []
172
32
  extra_rdoc_files: []
173
33
  files:
174
- - ".gitignore"
175
- - ".rspec"
176
- - ".rubocop.yml"
177
- - ".rubocop_todo.yml"
178
- - ".travis.yml"
179
- - CHANGELOG.md
180
- - CODE_OF_CONDUCT.md
181
- - Gemfile
182
34
  - LICENSE.txt
183
35
  - README.md
184
- - Rakefile
185
36
  - bin/console
186
37
  - bin/setup
187
38
  - fusuma-plugin-wmctrl.gemspec
188
39
  - lib/fusuma/plugin/executors/wmctrl_executor.rb
189
40
  - lib/fusuma/plugin/wmctrl.rb
190
41
  - lib/fusuma/plugin/wmctrl/version.rb
42
+ - spec/fusuma/plugin/plugin/executors/wmctrl_executor_spec.rb
43
+ - spec/fusuma/plugin/wmctrl_spec.rb
44
+ - spec/helpers/config_helper.rb
45
+ - spec/spec_helper.rb
191
46
  homepage: https://github.com/iberianpig/fusuma-plugin-wmctrl
192
47
  licenses:
193
48
  - MIT
@@ -207,8 +62,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
62
  - !ruby/object:Gem::Version
208
63
  version: '0'
209
64
  requirements: []
210
- rubygems_version: 3.0.3
65
+ rubygems_version: 3.1.4
211
66
  signing_key:
212
67
  specification_version: 4
213
68
  summary: Wmctrl plugin for Fusuma
214
- test_files: []
69
+ test_files:
70
+ - spec/fusuma/plugin/plugin/executors/wmctrl_executor_spec.rb
71
+ - spec/fusuma/plugin/wmctrl_spec.rb
72
+ - spec/helpers/config_helper.rb
73
+ - spec/spec_helper.rb
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
-
11
- # rspec failure tracking
12
- .rspec_status
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,15 +0,0 @@
1
- inherit_from: .rubocop_todo.yml
2
-
3
- Metrics/ModuleLength:
4
- Exclude:
5
- - "**/*_spec.rb"
6
-
7
- Metrics/BlockLength:
8
- Exclude:
9
- - "**/*_spec.rb"
10
- - "fusuma-plugin-*.gemspec"
11
-
12
- Metrics/LineLength:
13
- Max: 100
14
- Exclude:
15
- - "fusuma-plugin-*.gemspec"
data/.rubocop_todo.yml DELETED
File without changes
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.3.1
7
- - 2.4
8
- - 2.5
9
- - 2.6
10
- before_install: gem install bundler --no-document -v 2.0.1
data/CHANGELOG.md DELETED
@@ -1,5 +0,0 @@
1
- # Change Log
2
-
3
-
4
-
5
- \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at yhkyky@gmail.com. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in fusuma-plugin-wmctrl.gemspec
6
- gemspec
data/Rakefile DELETED
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: :spec
9
-
10
- require 'github_changelog_generator/task'
11
-
12
- GitHubChangelogGenerator::RakeTask.new :changelog do |config|
13
- config.user = 'iberianpig'
14
- config.project = 'fusuma-plugin-wmctrl'
15
- end