exfuz 0.1.0

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.
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'curses'
4
+
5
+ module Exfuz
6
+ class Screen
7
+ attr_reader :query
8
+
9
+ def initialize(status = nil, key_map = nil, candidates = nil)
10
+ @conf = Exfuz::Configuration.instance
11
+
12
+ @status = status
13
+ @prev_loaded = @status.loaded
14
+ @key_map = key_map
15
+ @prompt = '>'
16
+ @query = Exfuz::Query.new([0, @prompt.size])
17
+ @cmd = Exfuz::FuzzyFinderCommand.new(command_type: @conf.fuzzy_finder_command_type)
18
+ @candidates = candidates
19
+
20
+ @description = Exfuz::Body.new(top: 1, bottom: 1, texts: ['please input query'])
21
+ @list = Exfuz::Body.new(top: 2, bottom: 4)
22
+
23
+ register_event
24
+ end
25
+
26
+ def status
27
+ @status.to_s
28
+ end
29
+
30
+ def init
31
+ Curses.init_screen
32
+ # キー入力の文字を画面に反映させない
33
+ Curses.noecho
34
+ # 入力の待機時間(milliseconds)
35
+ Curses.timeout = 100
36
+
37
+ @list.bottom = Curses.lines - @list.top + 1
38
+ draw
39
+ Curses.refresh
40
+ end
41
+
42
+ def rerender
43
+ @prev_loaded = @status.loaded
44
+ refresh
45
+ end
46
+
47
+ def refresh
48
+ draw
49
+ Curses.refresh
50
+ end
51
+
52
+ def wait_input
53
+ @ch = Curses.getch
54
+ # 待機時間内に入力されない場合
55
+ return unless @ch
56
+
57
+ handle_event(@ch)
58
+ end
59
+
60
+ # 表示内容の変更検知を判定する
61
+ def changed_state?
62
+ @prev_loaded < @status.loaded
63
+ end
64
+
65
+ def closed?
66
+ Curses.closed?
67
+ end
68
+
69
+ def close
70
+ Curses.close_screen
71
+ end
72
+
73
+ # event
74
+ def start_cmd
75
+ filtered = @candidates.filter({ textable: @query.text })
76
+ @cmd.run do |fiber|
77
+ filtered.positions.each_with_index do |position, idx|
78
+ value_text = position.textable.value.to_s
79
+ line = [
80
+ idx,
81
+ position.book_name.relative_path,
82
+ position.sheet_name.name,
83
+ position.textable.position_s(format: @conf.cell_position_format),
84
+ @conf.split_new_line ? value_text : value_text.gsub(/\R+/) { '\n' }
85
+ ].join(@conf.line_sep)
86
+ fiber.resume(line)
87
+ end
88
+ end
89
+
90
+ selected_positions = @cmd.selected.map do |s|
91
+ idx = s.split(@conf.line_sep).first.to_i
92
+ filtered.positions[idx]
93
+ end
94
+
95
+ if Exfuz::Util.wsl? && @conf.jump_positions?
96
+ jump = Exfuz::Jump.new(selected_positions)
97
+ jump.run
98
+ end
99
+
100
+ @list.change_all(@cmd.selected)
101
+
102
+ Curses.clear
103
+ init
104
+ end
105
+
106
+ def delete_char
107
+ @query.delete
108
+ refresh
109
+ end
110
+
111
+ def move_left
112
+ @query.left
113
+ refresh
114
+ end
115
+
116
+ def move_right
117
+ @query.right
118
+ refresh
119
+ end
120
+
121
+ def move_prev_page
122
+ @list.move_prev
123
+ refresh
124
+ end
125
+
126
+ def move_next_page
127
+ @list.move_next
128
+ refresh
129
+ end
130
+
131
+ def finish
132
+ close
133
+ end
134
+
135
+ def insert_char(char)
136
+ @query.add(char)
137
+ refresh
138
+ end
139
+
140
+ private
141
+
142
+ def handle_event(ch)
143
+ input = if Exfuz::Key.can_convert_to_name_and_char?(ch)
144
+ ch
145
+ else
146
+ chs = [ch]
147
+ # スレッドセーフでないかも
148
+ # 稀に正常にchが読み込めない場合があった
149
+ loop do
150
+ remaining = Curses.getch
151
+ break if remaining.nil?
152
+
153
+ chs << remaining
154
+ end
155
+ chs
156
+ end
157
+
158
+ name, char = Exfuz::Key.input_to_name_and_char(input)
159
+
160
+ char.nil? ? @key_map.pressed(name) : @key_map.pressed(name, char)
161
+ end
162
+
163
+ def register_event
164
+ @key_map.add_event_handler(Exfuz::Key::CTRL_R, self, func: :start_cmd)
165
+ @key_map.add_event_handler(Exfuz::Key::CTRL_E, self, func: :finish)
166
+ @key_map.add_event_handler(Exfuz::Key::CTRL_L, self, func: :move_next_page)
167
+ @key_map.add_event_handler(Exfuz::Key::CTRL_H, self, func: :move_prev_page)
168
+ @key_map.add_event_handler(Exfuz::Key::LEFT, self, func: :move_left)
169
+ @key_map.add_event_handler(Exfuz::Key::RIGHT, self, func: :move_right)
170
+ @key_map.add_event_handler(Exfuz::Key::BACKSPACE, self, func: :delete_char)
171
+ @key_map.add_event_handler(Exfuz::Key::CHAR, self, func: :insert_char)
172
+ end
173
+
174
+ def draw
175
+ print_head_line
176
+
177
+ print_description
178
+
179
+ print_body
180
+
181
+ reset_caret
182
+ end
183
+
184
+ def reset_caret
185
+ Curses.setpos(*@query.caret)
186
+ end
187
+
188
+ def print_head_line
189
+ # 前回の入力内容を保持してないためクエリの全文字を再描画
190
+ Curses.setpos(0, 0)
191
+ Curses.addstr(@prompt + @query.line)
192
+
193
+ col = Curses.cols - status.size
194
+ Curses.setpos(0, col)
195
+ Curses.addstr(status)
196
+ end
197
+
198
+ def print_description
199
+ @description.lines.each do |row, line|
200
+ print_line(row: row, line: line)
201
+ end
202
+ end
203
+
204
+ def print_body
205
+ @list.lines(overwrite: true).each do |row, line|
206
+ print_line(row: row, line: line)
207
+ end
208
+ end
209
+
210
+ def print_line(row:, line:)
211
+ Curses.setpos(row, 0)
212
+ Curses.addstr(line)
213
+ end
214
+ end
215
+ end
216
+
217
+ def main
218
+ require_relative './status'
219
+ screen = Exfuz::Screen.new(Exfuz::Status.new(10))
220
+ screen.init
221
+ until screen.closed?
222
+ # キー入力を待機
223
+ screen.handle_input
224
+ end
225
+ screen.close
226
+ end
227
+
228
+ main if __FILE__ == $0
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exfuz
4
+ class SheetName
5
+ def self.name
6
+ :sheet_name
7
+ end
8
+
9
+ attr_reader :name
10
+
11
+ include Exfuz::Util
12
+
13
+ def initialize(name)
14
+ @name = @text = name
15
+ end
16
+
17
+ def ==(other)
18
+ return false if other.nil? || !other.instance_of?(Exfuz::SheetName)
19
+
20
+ name == other.name
21
+ end
22
+
23
+ def hash
24
+ @name.hash
25
+ end
26
+
27
+ def jump_info
28
+ { Exfuz::SheetName.name => @name }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exfuz
4
+ class Status
5
+ attr_reader :loaded, :max
6
+
7
+ def initialize(max)
8
+ @loaded = 0
9
+ @max = max
10
+ end
11
+
12
+ def update(num)
13
+ @loaded += num
14
+ end
15
+
16
+ def finished?
17
+ @loaded == @max
18
+ end
19
+
20
+ # TODO: メソッド名を変更すること
21
+ def to_s
22
+ "[#{@loaded}/#{@max}]"
23
+ end
24
+ end
25
+ end
data/lib/exfuz/util.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'etc'
4
+
5
+ module Exfuz
6
+ module Util
7
+ def match?(word)
8
+ regexp = Regexp.new(word.downcase, Regexp::IGNORECASE)
9
+ @text.match?(regexp)
10
+ end
11
+
12
+ module_function
13
+
14
+ def wsl?
15
+ Etc.uname[:release].match?(/.*microsoft.*/)
16
+ end
17
+
18
+ def wsl_to_windows(path)
19
+ nil unless wsl?
20
+
21
+ raise ArgumentError, 'not exists path' unless File.exist?(path)
22
+
23
+ `wslpath -w #{path}`.chomp
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Exfuz
4
+ VERSION = "0.1.0"
5
+ end
data/lib/exfuz.rb ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'exfuz/version'
4
+
5
+ module Exfuz
6
+ class Error < StandardError; end
7
+ autoload :BookName, 'exfuz/book_name'
8
+ autoload :Body, 'exfuz/body'
9
+ autoload :Candidate, 'exfuz/candidate'
10
+ autoload :Candidates, 'exfuz/candidates'
11
+ autoload :Cell, 'exfuz/cell'
12
+ autoload :Configuration, 'exfuz/configuration'
13
+ autoload :Command, 'exfuz/command'
14
+ autoload :Event, 'exfuz/event'
15
+ autoload :FuzzyFinderCommand, 'exfuz/fuzzy_finder_command'
16
+ autoload :Group, 'exfuz/group'
17
+ autoload :Jump, 'exfuz/jump'
18
+ autoload :Key, 'exfuz/key_map'
19
+ autoload :KeyMap, 'exfuz/key_map'
20
+ autoload :Parser, 'exfuz/parser'
21
+ autoload :Position, 'exfuz/position'
22
+ autoload :Query, 'exfuz/query'
23
+ autoload :Screen, 'exfuz/screen'
24
+ autoload :SheetName, 'exfuz/sheet_name'
25
+ autoload :Status, 'exfuz/status'
26
+ autoload :Util, 'exfuz/util'
27
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: exfuz
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - wata00913
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-01-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Fuzzy finder excel. This uses a fuzzy finder such as peco or fzf.
14
+ email:
15
+ - 175d8639@gmail.com
16
+ executables:
17
+ - exfuz
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - ".rspec"
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - README.md
26
+ - Rakefile
27
+ - bin/console
28
+ - bin/setup
29
+ - exe/exfuz
30
+ - exfuz.gemspec
31
+ - lib/exfuz.rb
32
+ - lib/exfuz/body.rb
33
+ - lib/exfuz/book_name.rb
34
+ - lib/exfuz/candidate.rb
35
+ - lib/exfuz/candidates.rb
36
+ - lib/exfuz/cell.rb
37
+ - lib/exfuz/command.rb
38
+ - lib/exfuz/configuration.rb
39
+ - lib/exfuz/event.rb
40
+ - lib/exfuz/fuzzy_finder_command.rb
41
+ - lib/exfuz/group.rb
42
+ - lib/exfuz/jump.rb
43
+ - lib/exfuz/key_map.rb
44
+ - lib/exfuz/main.rb
45
+ - lib/exfuz/operator.ps1
46
+ - lib/exfuz/parser.rb
47
+ - lib/exfuz/position.rb
48
+ - lib/exfuz/query.rb
49
+ - lib/exfuz/screen.rb
50
+ - lib/exfuz/sheet_name.rb
51
+ - lib/exfuz/status.rb
52
+ - lib/exfuz/util.rb
53
+ - lib/exfuz/version.rb
54
+ homepage: https://github.com/wata00913/exfuz
55
+ licenses: []
56
+ metadata: {}
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: 2.4.0
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubygems_version: 3.2.22
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: excel fuzzy finder
76
+ test_files: []