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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +44 -0
- data/README.md +88 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/exfuz +4 -0
- data/exfuz.gemspec +24 -0
- data/lib/exfuz/body.rb +105 -0
- data/lib/exfuz/book_name.rb +36 -0
- data/lib/exfuz/candidate.rb +48 -0
- data/lib/exfuz/candidates.rb +53 -0
- data/lib/exfuz/cell.rb +82 -0
- data/lib/exfuz/command.rb +11 -0
- data/lib/exfuz/configuration.rb +86 -0
- data/lib/exfuz/event.rb +17 -0
- data/lib/exfuz/fuzzy_finder_command.rb +37 -0
- data/lib/exfuz/group.rb +34 -0
- data/lib/exfuz/jump.rb +29 -0
- data/lib/exfuz/key_map.rb +116 -0
- data/lib/exfuz/main.rb +59 -0
- data/lib/exfuz/operator.ps1 +62 -0
- data/lib/exfuz/parser.rb +67 -0
- data/lib/exfuz/position.rb +63 -0
- data/lib/exfuz/query.rb +103 -0
- data/lib/exfuz/screen.rb +228 -0
- data/lib/exfuz/sheet_name.rb +31 -0
- data/lib/exfuz/status.rb +25 -0
- data/lib/exfuz/util.rb +26 -0
- data/lib/exfuz/version.rb +5 -0
- data/lib/exfuz.rb +27 -0
- metadata +76 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9b0a899fb5743a6cd65c434e4be0853019ddcf1856bdd27515518fe5a04e9716
|
|
4
|
+
data.tar.gz: a8d191ed60ffcba306c483027351176b90a800b494017ca049c4a9382d68ea01
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 879270cc6ab2a5e08d979d9d88995362f09ea5be623f9a9b95d54aca8e4fe35ea997625da92bfb56740d31c8a44edbe781255ba7d514bd793e086b6ffad31006
|
|
7
|
+
data.tar.gz: 3eebc206ab2ad1780a4c9254642fe33e8635ed4f8b09cb083c775c8fe10eb9e15d25ab875067acac4c9f3f9a10944450b77e29275a5f89e9e29cc76776f719fe
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
exfuz (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
curses (1.4.4)
|
|
10
|
+
diff-lcs (1.5.0)
|
|
11
|
+
rake (13.0.3)
|
|
12
|
+
rspec (3.11.0)
|
|
13
|
+
rspec-core (~> 3.11.0)
|
|
14
|
+
rspec-expectations (~> 3.11.0)
|
|
15
|
+
rspec-mocks (~> 3.11.0)
|
|
16
|
+
rspec-core (3.11.0)
|
|
17
|
+
rspec-support (~> 3.11.0)
|
|
18
|
+
rspec-expectations (3.11.0)
|
|
19
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
20
|
+
rspec-support (~> 3.11.0)
|
|
21
|
+
rspec-mocks (3.11.0)
|
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
23
|
+
rspec-support (~> 3.11.0)
|
|
24
|
+
rspec-support (3.11.0)
|
|
25
|
+
rubyzip (2.3.2)
|
|
26
|
+
thor (1.2.1)
|
|
27
|
+
unicode-display_width (2.3.0)
|
|
28
|
+
xsv (1.1.1)
|
|
29
|
+
rubyzip (>= 1.3, < 3)
|
|
30
|
+
|
|
31
|
+
PLATFORMS
|
|
32
|
+
x86_64-darwin-19
|
|
33
|
+
|
|
34
|
+
DEPENDENCIES
|
|
35
|
+
curses
|
|
36
|
+
exfuz!
|
|
37
|
+
rake (~> 13.0)
|
|
38
|
+
rspec (~> 3.0)
|
|
39
|
+
thor
|
|
40
|
+
unicode-display_width
|
|
41
|
+
xsv
|
|
42
|
+
|
|
43
|
+
BUNDLED WITH
|
|
44
|
+
2.2.24
|
data/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# exfuz
|
|
2
|
+
|
|
3
|
+
exfuz is able to fuzzy search for excel by using fuzzy finder tools such as fzf, peco
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- fuzzy search is possible for excel workbook, sheet, cells
|
|
8
|
+
- note: In the current version, exfuz cannot be used if the Ruby environment is Windows.
|
|
9
|
+
- can jump to positions selected lines by fuzzy finder tools
|
|
10
|
+
- note: In the current version, the jump function is only available in wsl.
|
|
11
|
+
|
|
12
|
+
## Demo
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
gem install exfuz
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Install the fuzzy finder tool.[^1]
|
|
22
|
+
[^1]:One of the following fuzzy finder tools must be installed in advance.</br>
|
|
23
|
+
・[fzf](https://github.com/junegunn/fzf)</br>
|
|
24
|
+
・[peco](https://github.com/peco/peco)</br>
|
|
25
|
+
・[percol](https://github.com/mooz/percol)</br>
|
|
26
|
+
・[skim](https://github.com/lotabout/skim)
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
exfuz start
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Sources to be searched are xlsx files under the current directory hierarchy.
|
|
35
|
+
|
|
36
|
+
### Query
|
|
37
|
+
It is possible to enter a query on the initial screen. Only cells matching the query will be subject to fuzzy search.</br>
|
|
38
|
+
For example, in the figure below, enter the regular expression `test.*data` in the query area.
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
### Item Format
|
|
42
|
+
The format of the items read by fuzzy finder tool is as follows.</br>
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
LineNumber:FileName:SheetName:CellAddress:CellValue
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`LineNumber` is the order of the data passed to the standard input. Also, the delimiter character for each content is`:`.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Key binding
|
|
52
|
+
|
|
53
|
+
| Key | Description |
|
|
54
|
+
|-------------|-----------------------------------------|
|
|
55
|
+
| CTRL-R | Launch Fuzzy Finder tool |
|
|
56
|
+
| CTRL-E | Stop exfuz |
|
|
57
|
+
| CTRL-H | Back to previous page of selection list |
|
|
58
|
+
| CTRL-L | Go to next page of selection list |
|
|
59
|
+
| Right Arrow | Move Query cursor to right |
|
|
60
|
+
| Left Arrow | Move Query cursor to left |
|
|
61
|
+
| BACKSPACE | Delete one character in Query |
|
|
62
|
+
|
|
63
|
+
## Options
|
|
64
|
+
|
|
65
|
+
Setting file is `.exfuz.json` .
|
|
66
|
+
|
|
67
|
+
The priority for reading the configuration is as follows.
|
|
68
|
+
|
|
69
|
+
1. `./.exfuz.json`
|
|
70
|
+
2. `~/.config/exfuz/.exfuz.json`
|
|
71
|
+
3. Default settings
|
|
72
|
+
|
|
73
|
+
| Option | Values / Default Value | Description |
|
|
74
|
+
|---------------------------|-----------------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
|
75
|
+
| book_name_path_type | [”relative”, “absolute”] </br> Default Value: "relative" | Format to display book name. </br> relative path or absolute path. |
|
|
76
|
+
| cell_position_format | [”index”, “address”] </br> Default Value: "address" | Format to display cell position </br> ex) index: $3$4, address: $C$4 |
|
|
77
|
+
| line_sep | Arbitary character </br> Default Value: ":" | Delimiter char </br> ex) book1.xlsx:sheet1:$A$1:value if delimiter char is : |
|
|
78
|
+
| split_new_line | [true, false] </br> Default Value: false | Whether to escape line breaks in cells |
|
|
79
|
+
| fuzzy_finder_command_type | ["fzf", "peco", "percol", "sk"][^2] </br> Default Value: "fzf" | Which fuzzy finder tool to use |
|
|
80
|
+
[^2]: Value to fuzzy finder tool is as followeds. </br>
|
|
81
|
+
・"fzf": fzf</br>
|
|
82
|
+
・"peco": peco</br>
|
|
83
|
+
・"percol": percol</br>
|
|
84
|
+
・"sk": skim
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT)
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "exfuz"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require "irb"
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/exfuz
ADDED
data/exfuz.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('./lib', __FILE__))
|
|
4
|
+
require_relative "lib/exfuz/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "exfuz"
|
|
8
|
+
spec.version = Exfuz::VERSION
|
|
9
|
+
spec.authors = ["wata00913"]
|
|
10
|
+
spec.email = ["175d8639@gmail.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = "excel fuzzy finder"
|
|
13
|
+
spec.description = "Fuzzy finder excel. This uses a fuzzy finder such as peco or fzf."
|
|
14
|
+
spec.homepage = "https://github.com/wata00913/exfuz"
|
|
15
|
+
spec.required_ruby_version = ">= 2.4.0"
|
|
16
|
+
|
|
17
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
19
|
+
end
|
|
20
|
+
spec.bindir = "exe"
|
|
21
|
+
spec.executables = ["exfuz"]
|
|
22
|
+
spec.require_paths = ["lib"]
|
|
23
|
+
|
|
24
|
+
end
|
data/lib/exfuz/body.rb
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Exfuz
|
|
4
|
+
class Body
|
|
5
|
+
attr_reader :top, :bottom
|
|
6
|
+
|
|
7
|
+
def initialize(texts: [], top: 0, bottom: 10)
|
|
8
|
+
@top = top
|
|
9
|
+
@bottom = bottom
|
|
10
|
+
|
|
11
|
+
@prev_row_to_text = {}
|
|
12
|
+
|
|
13
|
+
@size = bottom - top + 1
|
|
14
|
+
@texts = init_texts(texts)
|
|
15
|
+
init_page(@texts, @size)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def move_next
|
|
19
|
+
return if @current_page == @max_page
|
|
20
|
+
|
|
21
|
+
@current_page += 1
|
|
22
|
+
|
|
23
|
+
offset = (@current_page - 1) * @size
|
|
24
|
+
next_texts = @texts.slice(offset, @size).each_with_index.each_with_object({}) do |(text, idx), result|
|
|
25
|
+
result[idx] = text
|
|
26
|
+
end
|
|
27
|
+
change_some(next_texts)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def move_prev
|
|
31
|
+
return if @current_page == 1
|
|
32
|
+
|
|
33
|
+
@current_page -= 1
|
|
34
|
+
|
|
35
|
+
offset = (@current_page - 1) * @size
|
|
36
|
+
prev_texts = @texts.slice(offset, @size).each_with_index.each_with_object({}) do |(text, idx), result|
|
|
37
|
+
result[idx] = text
|
|
38
|
+
end
|
|
39
|
+
change_some(prev_texts)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def change(texts)
|
|
43
|
+
change_some(texts)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def change_some(texts)
|
|
47
|
+
texts.each do |line_num, text|
|
|
48
|
+
@prev_row_to_text[row(line_num)] = @row_to_text[row(line_num)] if @row_to_text.key?(row(line_num))
|
|
49
|
+
@row_to_text[row(line_num)] = text
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def change_all(texts)
|
|
54
|
+
@texts = init_texts(texts)
|
|
55
|
+
@prev_row_to_text = @row_to_text
|
|
56
|
+
init_page(texts, @size)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def lines(overwrite: false)
|
|
60
|
+
return @row_to_text unless overwrite
|
|
61
|
+
|
|
62
|
+
overwrite_lines = @prev_row_to_text.each_with_object({}) do |(row, prev_text), result|
|
|
63
|
+
current_text = @row_to_text[row] || ''
|
|
64
|
+
result[row] = overwrite(current: current_text, prev: prev_text)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
@row_to_text.merge(overwrite_lines)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def clear_prev
|
|
71
|
+
@prev_row_to_text = {}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def bottom=(bottom)
|
|
75
|
+
@bottom = bottom
|
|
76
|
+
@size = @bottom - top + 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def row(idx)
|
|
82
|
+
idx + @top
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def init_texts(texts)
|
|
86
|
+
@texts = texts + [''] * (@size - (texts.size % @size))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def init_page(texts, size)
|
|
90
|
+
@max_page = texts.size.zero? ? 1 : (texts.size.to_f / size).ceil
|
|
91
|
+
@current_page = 1
|
|
92
|
+
@row_to_text = texts.slice(0, size).each_with_index.each_with_object({}) do |(text, idx), result|
|
|
93
|
+
result[row(idx)] = text
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def overwrite(current:, prev:)
|
|
98
|
+
if current.size < prev.size
|
|
99
|
+
current.ljust(prev.size)
|
|
100
|
+
else
|
|
101
|
+
current
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
module Exfuz
|
|
6
|
+
class BookName
|
|
7
|
+
def self.name
|
|
8
|
+
:book_name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_reader :absolute_path
|
|
12
|
+
|
|
13
|
+
include Exfuz::Util
|
|
14
|
+
|
|
15
|
+
def initialize(file_name)
|
|
16
|
+
@absolute_path = @text = File.absolute_path(file_name)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ==(other)
|
|
20
|
+
absolute_path == other.absolute_path
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def hash
|
|
24
|
+
absolute_path.hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def relative_path
|
|
28
|
+
Pathname.new(@absolute_path).relative_path_from(Dir.pwd).to_s
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def jump_info
|
|
32
|
+
path = wsl? ? wsl_to_windows(@absolute_path) : @absolute_path
|
|
33
|
+
{ Exfuz::BookName.name => path }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
module Exfuz
|
|
6
|
+
class Candidate
|
|
7
|
+
def initialize(book_name:, sheet_name:, textable:)
|
|
8
|
+
@book_name = book_name
|
|
9
|
+
@sheet_name = sheet_name
|
|
10
|
+
@textable = textable
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def value
|
|
14
|
+
@textable.value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_line
|
|
18
|
+
@conf ||= Exfuz::Configuration.instance
|
|
19
|
+
[
|
|
20
|
+
book_name_line,
|
|
21
|
+
@sheet_name,
|
|
22
|
+
textable_position_line,
|
|
23
|
+
value_line
|
|
24
|
+
].join(@conf.line_sep)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def book_name_line
|
|
30
|
+
pname = Pathname.new(@book_name)
|
|
31
|
+
case @conf.book_name_path_type
|
|
32
|
+
when :relative
|
|
33
|
+
pname.relative_path_from(@conf.dirname.to_s)
|
|
34
|
+
when :absolute
|
|
35
|
+
@book_name
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def textable_position_line
|
|
40
|
+
@textable.position_s(format: @conf.cell_position_format)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def value_line
|
|
44
|
+
text = @textable.value.to_s
|
|
45
|
+
@conf.split_new_line ? text : text.gsub(/\R+/) { '\n' }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Exfuz
|
|
4
|
+
class Candidates
|
|
5
|
+
@@queue = Queue.new
|
|
6
|
+
@@raw = []
|
|
7
|
+
|
|
8
|
+
def initialize(items = [])
|
|
9
|
+
@processed = items
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def push(item)
|
|
13
|
+
@@queue << item
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def suspend_push
|
|
17
|
+
@@queue << nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def close_push?
|
|
21
|
+
@@queue.closed?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def close_push
|
|
25
|
+
@@queue << nil
|
|
26
|
+
@@queue.close
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def positions
|
|
30
|
+
@processed.empty? ? @@raw : @processed
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def filter(conditions)
|
|
34
|
+
pipeline
|
|
35
|
+
filtered = positions.filter do |position|
|
|
36
|
+
position.match?(conditions)
|
|
37
|
+
end
|
|
38
|
+
Exfuz::Candidates.new(filtered)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def group_by(keys)
|
|
42
|
+
pipeline
|
|
43
|
+
Exfuz::Group.new(positions, keys)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
def pipeline
|
|
48
|
+
while data = @@queue.pop
|
|
49
|
+
@processed << data
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/exfuz/cell.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Exfuz
|
|
4
|
+
class Cell
|
|
5
|
+
def self.name
|
|
6
|
+
:textable
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_reader :row, :col, :value
|
|
10
|
+
|
|
11
|
+
include Exfuz::Util
|
|
12
|
+
|
|
13
|
+
def initialize(value:, row: nil, col: nil, address: nil)
|
|
14
|
+
if row && col
|
|
15
|
+
@row = row
|
|
16
|
+
@col = col
|
|
17
|
+
elsif address
|
|
18
|
+
@row, @col = to_idx(address)
|
|
19
|
+
else
|
|
20
|
+
raise "argument error. row: #{row}, col: #{col}, address: #{address}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@value = value
|
|
24
|
+
# valueはString型以外も含むのでマッチ用の@textは文字列に変換させる
|
|
25
|
+
@text = @value.to_s
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def position_s(format: :address)
|
|
29
|
+
case format
|
|
30
|
+
when :address
|
|
31
|
+
to_address(@col, row)
|
|
32
|
+
when :index
|
|
33
|
+
"$#{col}$#{row}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ==(other)
|
|
38
|
+
return false if other.nil? || !other.instance_of?(Exfuz::Cell)
|
|
39
|
+
|
|
40
|
+
[@row, @col, @value] == [other.row, other.col, other.value]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def hash
|
|
44
|
+
[@row, @col, @value].hash
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def jump_info
|
|
48
|
+
{ Exfuz::Cell.name => { row: @row, col: @col } }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def to_idx(address)
|
|
54
|
+
_, c_alph, r_str = address.split('$')
|
|
55
|
+
|
|
56
|
+
c = 0
|
|
57
|
+
large_a_z = ('A'..'Z')
|
|
58
|
+
c_alph.chars.reverse.each_with_index do |char, i|
|
|
59
|
+
c += (26**i * (large_a_z.find_index(char) + 1))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
[r_str.to_i, c]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_address(col, row)
|
|
66
|
+
"$#{to_alphabet(col)}$#{row}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_alphabet(idx)
|
|
70
|
+
large_a_z = ('A'..'Z').to_a
|
|
71
|
+
alphabet = ''
|
|
72
|
+
q = idx
|
|
73
|
+
|
|
74
|
+
until q.zero?
|
|
75
|
+
q, r = (q - 1).divmod(26)
|
|
76
|
+
alphabet += large_a_z[r]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
alphabet
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'singleton'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
module Exfuz
|
|
8
|
+
class Configuration
|
|
9
|
+
include Singleton
|
|
10
|
+
|
|
11
|
+
GLOBAL_DIRS = [File.join(Dir.home, '.config/exfuz')].freeze
|
|
12
|
+
FILE_NAME = '.exfuz.json'
|
|
13
|
+
|
|
14
|
+
attr_reader :dirname
|
|
15
|
+
|
|
16
|
+
private_constant :FILE_NAME, :GLOBAL_DIRS
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
@dirname = Pathname.new(Dir.pwd)
|
|
20
|
+
set_data
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def book_name_path_type
|
|
24
|
+
@data[:book_name_path_type]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def cell_position_format
|
|
28
|
+
@data[:cell_position_format]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def line_sep
|
|
32
|
+
@data[:line_sep]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def split_new_line
|
|
36
|
+
@data[:split_new_line]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def jump_positions?
|
|
40
|
+
@data[:jump_positions]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def fuzzy_finder_command_type
|
|
44
|
+
@data[:fuzzy_finder_command_type].to_sym
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def set_data
|
|
50
|
+
@data = default.clone
|
|
51
|
+
@data.merge!(read_from_global || {})
|
|
52
|
+
.merge!(read_from_local(@dirname) || {})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def read_from_local(dirname)
|
|
56
|
+
fpath = File.join(dirname.to_s, FILE_NAME)
|
|
57
|
+
return nil unless File.exist?(fpath)
|
|
58
|
+
|
|
59
|
+
read(fpath)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def read_from_global
|
|
63
|
+
fpath = GLOBAL_DIRS.map { |d| File.join(d, FILE_NAME) }
|
|
64
|
+
.find { |f| File.exist?(f) }
|
|
65
|
+
return nil unless fpath
|
|
66
|
+
|
|
67
|
+
read(fpath)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def read(path)
|
|
71
|
+
data = JSON.parse(File.read(path), symbolize_names: true)
|
|
72
|
+
data.transform_values { |v| v.instance_of?(String) ? v.to_sym : v }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def default
|
|
76
|
+
{
|
|
77
|
+
book_name_path_type: :relative,
|
|
78
|
+
cell_position_format: :index,
|
|
79
|
+
line_sep: ':',
|
|
80
|
+
split_new_line: false,
|
|
81
|
+
jump_positions: false,
|
|
82
|
+
fuzzy_finder_command_type: 'fzf'
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/exfuz/event.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'observer'
|
|
4
|
+
|
|
5
|
+
module Exfuz
|
|
6
|
+
class Event
|
|
7
|
+
include Observable
|
|
8
|
+
def add_event_handler(obj, func)
|
|
9
|
+
add_observer(obj, func)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def fired(*args)
|
|
13
|
+
changed
|
|
14
|
+
args.empty? ? notify_observers : notify_observers(*args)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|