mk_semi_lattice 0.1.1
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/.DS_Store +0 -0
- data/.hyper_card/history/20251020_1517_readme_formatted.md +463 -0
- data/.hyper_card/history/20251020_1828_minor_rev_formatted.md +181 -0
- data/.hyper_card/history/20251021_1110_wsl_ubuntu_japanese.md +218 -0
- data/.hyper_card/history/20251021_1142_double_click_action.md +250 -0
- data/.hyper_card/history/20251021_1151_select_semi_data_action.md +75 -0
- data/.hyper_card/history/20251021_2322_add_comment_edges.md +252 -0
- data/.hyper_card/history/20251022_0725_add_color_index.md +155 -0
- data/.hyper_card/history/classify_251103.md +1090 -0
- data/.hyper_card/history/file_path_modifier.md +481 -0
- data/.hyper_card/history/file_path_modifier_251103.md +505 -0
- data/.hyper_card/history/knowledge_fixer.pdf +0 -0
- data/.hyper_card/history/log_with_symbol_251102.md +184 -0
- data/.hyper_card/history/memory_leak_251028.md +311 -0
- data/.hyper_card/history/set_log_conf_251027.md +295 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +8 -0
- data/exe/mk_semi_lattice +3 -0
- data/exe/sl +5 -0
- data/lib/mk_semi_lattice/config.rb +53 -0
- data/lib/mk_semi_lattice/log.rb +26 -0
- data/lib/mk_semi_lattice/manage_yaml.rb +89 -0
- data/lib/mk_semi_lattice/mk_dir_yaml.rb +40 -0
- data/lib/mk_semi_lattice/mk_node_edge.rb +108 -0
- data/lib/mk_semi_lattice/mk_semi_lattice_graph.rb +254 -0
- data/lib/mk_semi_lattice/mk_semi_lattice_viewer.rb +77 -0
- data/lib/mk_semi_lattice/option_manager.rb +58 -0
- data/lib/mk_semi_lattice/ruby2d_action.rb +136 -0
- data/lib/mk_semi_lattice/version.rb +5 -0
- data/lib/mk_semi_lattice.rb +22 -0
- data/sig/mk_semi_lattice.rbs +4 -0
- metadata +122 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
NODE_COLOR = 'orange'
|
|
2
|
+
SELECT_COLOR = 'red'
|
|
3
|
+
FIXED_COLOR = 'green'
|
|
4
|
+
LINKED_COLOR = 'blue'
|
|
5
|
+
EDGE_COLOR = 'black' # 標準色に戻す
|
|
6
|
+
|
|
7
|
+
# 日本語対応フォントの優先順位で選択 for win11, なければ省略
|
|
8
|
+
def japanese_font
|
|
9
|
+
fonts = [
|
|
10
|
+
'/usr/share/fonts/truetype/takao-gothic/TakaoGothic.ttf',
|
|
11
|
+
'/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf',
|
|
12
|
+
'/usr/share/fonts/truetype/fonts-japanese-gothic.ttf',
|
|
13
|
+
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc',
|
|
14
|
+
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
|
|
15
|
+
'/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf',
|
|
16
|
+
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
|
|
17
|
+
]
|
|
18
|
+
selected_font = fonts.find { |font| File.exist?(font) }
|
|
19
|
+
# puts "Selected font: #{selected_font}" if selected_font
|
|
20
|
+
selected_font || fonts.last
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Folder
|
|
24
|
+
# フォルダアイコンをRuby2Dの図形で描画するクラス
|
|
25
|
+
attr_accessor :x, :y, :name, :label, :fixed, :linked, :dx, :dy, :type, :file_path
|
|
26
|
+
def initialize(attrs = {})
|
|
27
|
+
@x = attrs[:x]
|
|
28
|
+
@y = attrs[:y]
|
|
29
|
+
@z = attrs[:z]
|
|
30
|
+
@color = attrs[:color]
|
|
31
|
+
@folder1 = Rectangle.new(x: @x-28, y: @y-10, width: 56, height: 32, color: @color, z: @z)
|
|
32
|
+
@folder2 = Rectangle.new(x: @x-28, y: @y-20, width: 32, height: 16, color: @color, z: @z)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def color= c
|
|
36
|
+
@folder1.color = c
|
|
37
|
+
@folder2.color = c
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def x= x
|
|
41
|
+
@folder1.x = x -28
|
|
42
|
+
@folder2.x = x -28
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def y= y
|
|
46
|
+
@folder1.y = y -10
|
|
47
|
+
@folder2.y = y -10
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Node
|
|
52
|
+
attr_accessor :x, :y, :name, :label, :fixed, :linked, :color, :dx, :dy, :type, :file_path
|
|
53
|
+
|
|
54
|
+
def initialize(attrs = {})
|
|
55
|
+
@name = attrs[:name]
|
|
56
|
+
@label = attrs[:label]
|
|
57
|
+
@x = attrs[:x] || rand(80..520)
|
|
58
|
+
@y = attrs[:y] || rand(80..520)
|
|
59
|
+
@fixed = attrs[:fixed] || false
|
|
60
|
+
@linked = attrs[:linked] || false
|
|
61
|
+
@color = attrs[:color] || NODE_COLOR
|
|
62
|
+
@dx = attrs[:dx] || 0.0
|
|
63
|
+
@dy = attrs[:dy] || 0.0
|
|
64
|
+
@type = attrs[:type]
|
|
65
|
+
@file_path = attrs[:file_path]
|
|
66
|
+
@circle = nil
|
|
67
|
+
@text = nil
|
|
68
|
+
@created = false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def update
|
|
72
|
+
unless fixed
|
|
73
|
+
@x += [@dx, -5, 5].sort[1]
|
|
74
|
+
@y += [@dy, -5, 5].sort[1]
|
|
75
|
+
|
|
76
|
+
@x = [[@x, 0].max, 600].min
|
|
77
|
+
@y = [[@y, 0].max, 600].min
|
|
78
|
+
end
|
|
79
|
+
@dx /= 2.0
|
|
80
|
+
@dy /= 2.0
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def relax(nodes)
|
|
84
|
+
ddx = 0
|
|
85
|
+
ddy = 0
|
|
86
|
+
|
|
87
|
+
nodes.each do |n|
|
|
88
|
+
next if n == self
|
|
89
|
+
|
|
90
|
+
vx = x - n.x
|
|
91
|
+
vy = y - n.y
|
|
92
|
+
lensq = vx * vx + vy * vy
|
|
93
|
+
|
|
94
|
+
if lensq == 0
|
|
95
|
+
ddx += rand(-1.0..1.0)
|
|
96
|
+
ddy += rand(-1.0..1.0)
|
|
97
|
+
elsif lensq < 100 * 100
|
|
98
|
+
ddx += vx / lensq
|
|
99
|
+
ddy += vy / lensq
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
dlen = Math.sqrt(ddx * ddx + ddy * ddy) / 2
|
|
104
|
+
if dlen > 0
|
|
105
|
+
@dx += ddx / dlen
|
|
106
|
+
@dy += ddy / dlen
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def create_graphics
|
|
111
|
+
return if @created
|
|
112
|
+
font_path = japanese_font
|
|
113
|
+
|
|
114
|
+
@circle = if @type == 'dir'
|
|
115
|
+
@text = if font_path && File.exist?(font_path)
|
|
116
|
+
Text.new(label, x: x-28, y: y-10, size: 18, color: 'black', font: font_path, z: 11)
|
|
117
|
+
else
|
|
118
|
+
Text.new(label, x: x-28, y: y-10, size: 18, color: 'black', z: 11)
|
|
119
|
+
end
|
|
120
|
+
Folder.new(x: x, y: y, color: NODE_COLOR, z: 10)
|
|
121
|
+
else
|
|
122
|
+
@text = if font_path && File.exist?(font_path)
|
|
123
|
+
Text.new(label, x: x-28, y: y-10, size: 18, color: 'black', font: font_path, z: 11)
|
|
124
|
+
else
|
|
125
|
+
Text.new(label, x: x-28, y: y-10, size: 18, color: 'black', z: 11)
|
|
126
|
+
end
|
|
127
|
+
Circle.new(x: x, y: y, radius: 30, color: NODE_COLOR, z: 10)
|
|
128
|
+
end
|
|
129
|
+
@created = true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def draw(selected)
|
|
133
|
+
create_graphics
|
|
134
|
+
|
|
135
|
+
c = if selected
|
|
136
|
+
SELECT_COLOR
|
|
137
|
+
elsif @fixed
|
|
138
|
+
FIXED_COLOR
|
|
139
|
+
elsif @linked
|
|
140
|
+
LINKED_COLOR
|
|
141
|
+
else
|
|
142
|
+
NODE_COLOR
|
|
143
|
+
end
|
|
144
|
+
@circle.color = c
|
|
145
|
+
@circle.x = @x
|
|
146
|
+
@circle.y = @y
|
|
147
|
+
@text.x = @x - 28
|
|
148
|
+
@text.y = @y
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
class Edge
|
|
153
|
+
attr_reader :from, :to
|
|
154
|
+
def initialize(from, to)
|
|
155
|
+
@from = from
|
|
156
|
+
@to = to
|
|
157
|
+
@len = 75.0
|
|
158
|
+
@line = nil
|
|
159
|
+
@created = nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def relax
|
|
163
|
+
vx = to.x - from.x
|
|
164
|
+
vy = to.y - from.y
|
|
165
|
+
d = Math.hypot(vx, vy)
|
|
166
|
+
if d > 0
|
|
167
|
+
f = (@len - d) / (d * 5)
|
|
168
|
+
dx = f * vx
|
|
169
|
+
dy = f * vy
|
|
170
|
+
to.dx += dx
|
|
171
|
+
to.dy += dy
|
|
172
|
+
from.dx -= dx
|
|
173
|
+
from.dy -= dy
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def update
|
|
178
|
+
# 何も処理しないが、将来拡張用
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def create_graphics
|
|
182
|
+
return if @created
|
|
183
|
+
@line = Line.new(
|
|
184
|
+
x1: from.x, y1: from.y, x2: to.x, y2: to.y,
|
|
185
|
+
width: 2, color: EDGE_COLOR, opacity: 0.3, z: 5 # opacityを追加
|
|
186
|
+
)
|
|
187
|
+
@created = true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def draw
|
|
191
|
+
create_graphics
|
|
192
|
+
# 既存ラインのプロパティを更新
|
|
193
|
+
@line.x1 = from.x
|
|
194
|
+
@line.y1 = from.y
|
|
195
|
+
@line.x2 = to.x
|
|
196
|
+
@line.y2 = to.y
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
class MkSemiLatticeGraphData
|
|
201
|
+
attr_reader :nodes, :edges, :node_table
|
|
202
|
+
attr_accessor :selected, :shift_pressed, :show_index
|
|
203
|
+
|
|
204
|
+
def initialize(file = "dir_node_edge.yaml", with_semi_lattice_yaml: false, show_index: false)
|
|
205
|
+
@nodes = []
|
|
206
|
+
@edges = []
|
|
207
|
+
@node_table = {}
|
|
208
|
+
@selected = nil
|
|
209
|
+
@shift_pressed = false
|
|
210
|
+
p @show_index = show_index
|
|
211
|
+
load_yaml_data_with_state(file, with_semi_lattice_yaml: with_semi_lattice_yaml)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def add_node(node_data)
|
|
215
|
+
return if node_data[:id].nil?
|
|
216
|
+
n = Node.new(node_data)
|
|
217
|
+
@nodes << n
|
|
218
|
+
@node_table[node_data[:id]] = n
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def add_edge(from_id, to_id)
|
|
222
|
+
from = @node_table[from_id]
|
|
223
|
+
to = @node_table[to_id]
|
|
224
|
+
@edges << Edge.new(from, to) if from && to
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def load_yaml_data_with_state(path, with_semi_lattice_yaml: false)
|
|
228
|
+
state_file = path
|
|
229
|
+
data = if with_semi_lattice_yaml && File.exist?(state_file)
|
|
230
|
+
YAML.load_file(state_file)
|
|
231
|
+
else
|
|
232
|
+
YAML.load_file(path, symbolize_names: true)
|
|
233
|
+
end
|
|
234
|
+
load_nodes_and_edges(data)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
private
|
|
238
|
+
|
|
239
|
+
def load_nodes_and_edges(data)
|
|
240
|
+
nodes_data = data[:nodes]
|
|
241
|
+
edges_data = data[:edges]
|
|
242
|
+
nodes_data.each do |node_data|
|
|
243
|
+
node_data[:label] = @show_index ?
|
|
244
|
+
"#{node_data[:id]}:#{node_data[:name]}" :
|
|
245
|
+
node_data[:name]
|
|
246
|
+
add_node(node_data)
|
|
247
|
+
end
|
|
248
|
+
edges_data.each do |edge_data|
|
|
249
|
+
from_id = edge_data[:from]
|
|
250
|
+
to_id = edge_data[:to]
|
|
251
|
+
add_edge(from_id, to_id)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
def mk_semi_lattice_viewer
|
|
2
|
+
puts "mk_semi_lattice is running... with method mk_semi_lattice_viewer"
|
|
3
|
+
|
|
4
|
+
Config.setup
|
|
5
|
+
|
|
6
|
+
option_manager = OptionManager.new
|
|
7
|
+
options = option_manager.parse!
|
|
8
|
+
|
|
9
|
+
parent_dir = Dir.pwd
|
|
10
|
+
semi_dir = File.join(parent_dir, '.semi_lattice')
|
|
11
|
+
semi_lattice_yaml_path = File.join(semi_dir, "semi_lattice.yaml")
|
|
12
|
+
|
|
13
|
+
Log.event("started", parent_dir: parent_dir)
|
|
14
|
+
|
|
15
|
+
selector = MkSemiLattice::ManageYaml.new(
|
|
16
|
+
parent_dir: parent_dir,
|
|
17
|
+
semi_dir: semi_dir,
|
|
18
|
+
semi_lattice_yaml_path: semi_lattice_yaml_path,
|
|
19
|
+
options: options
|
|
20
|
+
)
|
|
21
|
+
init_file, init_step = selector.select_init_file_and_step
|
|
22
|
+
p [init_file, init_step]
|
|
23
|
+
input_path, with_semi_lattice_yaml = selector.select_input_path_and_flag(init_file, init_step)
|
|
24
|
+
p [input_path, with_semi_lattice_yaml]
|
|
25
|
+
|
|
26
|
+
# options[:layer] を MkSemiLatticeGraphData に渡す
|
|
27
|
+
app = MkSemiLatticeGraphData.new(
|
|
28
|
+
input_path,
|
|
29
|
+
with_semi_lattice_yaml: with_semi_lattice_yaml,
|
|
30
|
+
show_index: options[:show_index],
|
|
31
|
+
# layer: options[:layer] # 追加
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
require 'ruby2d'
|
|
35
|
+
|
|
36
|
+
top_node_label = app.nodes.first&.label || "KnowledgeFixer Graph"
|
|
37
|
+
set width: 800, height: 600
|
|
38
|
+
set title: top_node_label
|
|
39
|
+
set background: 'white'
|
|
40
|
+
set fps: 15
|
|
41
|
+
|
|
42
|
+
last_click_time = nil
|
|
43
|
+
last_click_node = nil
|
|
44
|
+
|
|
45
|
+
on :key_down do |event|
|
|
46
|
+
Ruby2dAction.on_key_down(app, event)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
on :key_up do |event|
|
|
50
|
+
Ruby2dAction.on_key_up(app, event)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
on :mouse_down do |event|
|
|
54
|
+
clicked_node, last_time = Ruby2dAction.on_mouse_down(app, event, last_click_node, last_click_time, parent_dir)
|
|
55
|
+
last_click_node = clicked_node
|
|
56
|
+
last_click_time = last_time
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
on :mouse_up do
|
|
60
|
+
Ruby2dAction.on_mouse_up(app)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
on :mouse_move do |event|
|
|
64
|
+
Ruby2dAction.on_mouse_move(app, event)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
update do
|
|
68
|
+
Ruby2dAction.update_action(app)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
at_exit do
|
|
72
|
+
MkSemiLattice::ManageYaml.at_exit_action(app, semi_dir, parent_dir)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
show
|
|
76
|
+
|
|
77
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'optparse'
|
|
3
|
+
require 'colorize'
|
|
4
|
+
|
|
5
|
+
class OptionManager
|
|
6
|
+
attr_reader :options
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@options = { layer: 2, init_step: :from_semi_lattice, show_index: false, merge: false }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse!
|
|
13
|
+
OptionParser.new do |opts|
|
|
14
|
+
opts.banner = "Usage: mk_semi_lattice PATH [-L layer] [-t FILE] [-n FILE]\n default PATH = '.'"
|
|
15
|
+
|
|
16
|
+
opts.on("-L N", Integer, "Layer depth (default: 2)") do |v|
|
|
17
|
+
@options[:layer] = v
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
opts.on("-n", "--node=FILE", "using File from node-edge") do |file|
|
|
21
|
+
@options[:file] = file
|
|
22
|
+
@options[:init_step] = :from_node_edge
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
opts.on("-t", "--tree=FILE", "using File from tree") do |file|
|
|
26
|
+
@options[:file] = file
|
|
27
|
+
@options[:init_step] = :from_tree
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
opts.on("-i", "--index", "Display node ids") do
|
|
31
|
+
@options[:show_index] = true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
opts.on("-l", "--log [BOOL]", "Enable/disable logging (true/false), and save to config") do |v|
|
|
35
|
+
bool =
|
|
36
|
+
if v.nil?
|
|
37
|
+
true
|
|
38
|
+
elsif v.is_a?(String)
|
|
39
|
+
case v.strip.downcase
|
|
40
|
+
when "true", "yes", "on", "1"
|
|
41
|
+
true
|
|
42
|
+
when "false", "no", "off", "0"
|
|
43
|
+
false
|
|
44
|
+
else
|
|
45
|
+
puts "Invalid value for log: #{v}. Using default: false".yellow
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
!!v
|
|
50
|
+
end
|
|
51
|
+
Config.set_log(bool)
|
|
52
|
+
puts "Logging is now #{bool ? 'enabled' : 'disabled'} (saved to #{Config::CONF_PATH})"
|
|
53
|
+
exit
|
|
54
|
+
end
|
|
55
|
+
end.parse!
|
|
56
|
+
@options
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruby2dAction
|
|
4
|
+
def self.on_key_down(app, event)
|
|
5
|
+
app.shift_pressed = true if event.key.include?('shift')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.on_key_up(app, event)
|
|
9
|
+
app.shift_pressed = false if event.key.include?('shift')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.double_click?(clicked_node, last_click_node, last_click_time)
|
|
13
|
+
now = Time.now
|
|
14
|
+
if last_click_node == clicked_node && last_click_time && (now - last_click_time < 0.4)
|
|
15
|
+
return true, now
|
|
16
|
+
end
|
|
17
|
+
return false, now
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.auto_fp_modifier(parent_dir, file_path)
|
|
21
|
+
pd = File.expand_path(parent_dir)
|
|
22
|
+
fp = file_path.dup
|
|
23
|
+
|
|
24
|
+
# file_pathが"./"で始まる場合は除去
|
|
25
|
+
fp = fp.sub(%r{\A\./}, '')
|
|
26
|
+
|
|
27
|
+
# parent_dirのbasenameを取得
|
|
28
|
+
pd_base = File.basename(pd)
|
|
29
|
+
|
|
30
|
+
# parent_dirのパスの中にfile_pathの先頭要素が含まれている場合は、重複しないようにする
|
|
31
|
+
fp_first = fp.split(File::SEPARATOR).first
|
|
32
|
+
if fp == pd_base
|
|
33
|
+
# 完全一致ならparent_dir自身
|
|
34
|
+
pd
|
|
35
|
+
elsif pd.include?(fp_first) && fp.start_with?(fp_first + File::SEPARATOR)
|
|
36
|
+
# parent_dirのどこかにfile_pathの先頭要素が含まれている場合は、その要素以降をparent_dirに連結
|
|
37
|
+
idx = fp.index(File::SEPARATOR)
|
|
38
|
+
rest = idx ? fp[idx+1..-1] : ""
|
|
39
|
+
File.join(pd, rest)
|
|
40
|
+
else
|
|
41
|
+
File.expand_path(fp, pd)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.double_click_action(clicked_node, parent_dir)
|
|
46
|
+
comm = nil
|
|
47
|
+
if clicked_node.file_path
|
|
48
|
+
# URL判定
|
|
49
|
+
if clicked_node.file_path =~ /\Ahttps?:\/\//
|
|
50
|
+
abs_path = clicked_node.file_path
|
|
51
|
+
comm = "open '#{abs_path}'"
|
|
52
|
+
else
|
|
53
|
+
abs_path =
|
|
54
|
+
if Pathname.new(clicked_node.file_path).absolute?
|
|
55
|
+
clicked_node.file_path
|
|
56
|
+
else
|
|
57
|
+
auto_fp_modifier(parent_dir, clicked_node.file_path)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
puts "[DEBUG] parent_dir: #{parent_dir}"
|
|
61
|
+
puts "[DEBUG] file_path: #{clicked_node.file_path}"
|
|
62
|
+
puts "[DEBUG] abs_path: #{abs_path}"
|
|
63
|
+
|
|
64
|
+
if File.directory?(abs_path)
|
|
65
|
+
if RbConfig::CONFIG['host_os'] =~ /darwin/
|
|
66
|
+
comm = "open -a Terminal '#{abs_path}'"
|
|
67
|
+
elsif RbConfig::CONFIG['host_os'] =~ /debian/
|
|
68
|
+
comm = "gnome-terminal --working-directory='#{abs_path}'"
|
|
69
|
+
else
|
|
70
|
+
comm = "wt.exe -p Ubuntu-24.04 --colorScheme 'Tango Light' -d '#{abs_path}'"
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
comm = "open '#{abs_path}'"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
puts comm
|
|
77
|
+
Log.event("open", target_dir: abs_path, parent_dir: parent_dir)
|
|
78
|
+
system comm
|
|
79
|
+
else
|
|
80
|
+
puts "no link error"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.on_mouse_down(app, event, last_click_node, last_click_time, parent_dir)
|
|
85
|
+
mx, my = event.x, event.y
|
|
86
|
+
shift_down = !!app.shift_pressed
|
|
87
|
+
clicked_node = nil
|
|
88
|
+
app.nodes.each do |n|
|
|
89
|
+
if Math.hypot(n.x - mx, n.y - my) < 30
|
|
90
|
+
clicked_node = n
|
|
91
|
+
if shift_down
|
|
92
|
+
n.fixed = false
|
|
93
|
+
n.color = NODE_COLOR
|
|
94
|
+
app.selected = nil
|
|
95
|
+
else
|
|
96
|
+
app.selected = n
|
|
97
|
+
if event.button == :left
|
|
98
|
+
n.fixed = true
|
|
99
|
+
n.color = FIXED_COLOR
|
|
100
|
+
end
|
|
101
|
+
n.fixed = false if event.button == :middle
|
|
102
|
+
n.linked = true if event.button == :right
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# ダブルクリック判定とファイルオープン
|
|
108
|
+
if clicked_node
|
|
109
|
+
is_double, now = double_click?(clicked_node, last_click_node, last_click_time)
|
|
110
|
+
double_click_action(clicked_node, parent_dir) if is_double
|
|
111
|
+
return clicked_node, now
|
|
112
|
+
end
|
|
113
|
+
[last_click_node, last_click_time]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.on_mouse_up(app)
|
|
117
|
+
app.selected = nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.on_mouse_move(app, event)
|
|
121
|
+
if app.selected
|
|
122
|
+
app.selected.x = event.x
|
|
123
|
+
app.selected.y = event.y
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def self.update_action(app)
|
|
128
|
+
app.edges.each(&:relax)
|
|
129
|
+
app.nodes.each { |n| n.relax(app.nodes) }
|
|
130
|
+
app.nodes.each(&:update)
|
|
131
|
+
app.edges.reverse.each(&:draw)
|
|
132
|
+
app.nodes.reverse.each do |n|
|
|
133
|
+
n.draw(app.selected == n)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'optparse'
|
|
3
|
+
require 'command_line/global'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'colorize'
|
|
6
|
+
require 'rbconfig'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
|
|
9
|
+
require_relative "mk_semi_lattice/version"
|
|
10
|
+
require_relative "mk_semi_lattice/config"
|
|
11
|
+
require_relative "mk_semi_lattice/log"
|
|
12
|
+
require_relative "mk_semi_lattice/mk_dir_yaml"
|
|
13
|
+
require_relative "mk_semi_lattice/mk_node_edge"
|
|
14
|
+
require_relative "mk_semi_lattice/mk_semi_lattice_graph"
|
|
15
|
+
require_relative "mk_semi_lattice/option_manager"
|
|
16
|
+
require_relative "mk_semi_lattice/manage_yaml"
|
|
17
|
+
require_relative "mk_semi_lattice/ruby2d_action"
|
|
18
|
+
require_relative "mk_semi_lattice/mk_semi_lattice_viewer"
|
|
19
|
+
|
|
20
|
+
class Error < StandardError; end
|
|
21
|
+
|
|
22
|
+
mk_semi_lattice_viewer
|
metadata
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mk_semi_lattice
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Shigeto R. Nishitani
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: command_line
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: colorize
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ruby2d
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
description: make semi lattice graph from directory structure
|
|
55
|
+
email:
|
|
56
|
+
- shigeto_nishitani@me.com
|
|
57
|
+
executables:
|
|
58
|
+
- mk_semi_lattice
|
|
59
|
+
- sl
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- ".DS_Store"
|
|
64
|
+
- ".hyper_card/history/20251020_1517_readme_formatted.md"
|
|
65
|
+
- ".hyper_card/history/20251020_1828_minor_rev_formatted.md"
|
|
66
|
+
- ".hyper_card/history/20251021_1110_wsl_ubuntu_japanese.md"
|
|
67
|
+
- ".hyper_card/history/20251021_1142_double_click_action.md"
|
|
68
|
+
- ".hyper_card/history/20251021_1151_select_semi_data_action.md"
|
|
69
|
+
- ".hyper_card/history/20251021_2322_add_comment_edges.md"
|
|
70
|
+
- ".hyper_card/history/20251022_0725_add_color_index.md"
|
|
71
|
+
- ".hyper_card/history/classify_251103.md"
|
|
72
|
+
- ".hyper_card/history/file_path_modifier.md"
|
|
73
|
+
- ".hyper_card/history/file_path_modifier_251103.md"
|
|
74
|
+
- ".hyper_card/history/knowledge_fixer.pdf"
|
|
75
|
+
- ".hyper_card/history/log_with_symbol_251102.md"
|
|
76
|
+
- ".hyper_card/history/memory_leak_251028.md"
|
|
77
|
+
- ".hyper_card/history/set_log_conf_251027.md"
|
|
78
|
+
- CHANGELOG.md
|
|
79
|
+
- CODE_OF_CONDUCT.md
|
|
80
|
+
- LICENSE.txt
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- exe/mk_semi_lattice
|
|
84
|
+
- exe/sl
|
|
85
|
+
- lib/mk_semi_lattice.rb
|
|
86
|
+
- lib/mk_semi_lattice/config.rb
|
|
87
|
+
- lib/mk_semi_lattice/log.rb
|
|
88
|
+
- lib/mk_semi_lattice/manage_yaml.rb
|
|
89
|
+
- lib/mk_semi_lattice/mk_dir_yaml.rb
|
|
90
|
+
- lib/mk_semi_lattice/mk_node_edge.rb
|
|
91
|
+
- lib/mk_semi_lattice/mk_semi_lattice_graph.rb
|
|
92
|
+
- lib/mk_semi_lattice/mk_semi_lattice_viewer.rb
|
|
93
|
+
- lib/mk_semi_lattice/option_manager.rb
|
|
94
|
+
- lib/mk_semi_lattice/ruby2d_action.rb
|
|
95
|
+
- lib/mk_semi_lattice/version.rb
|
|
96
|
+
- sig/mk_semi_lattice.rbs
|
|
97
|
+
homepage: https://github.com/daddygongon/mk_semi_lattice
|
|
98
|
+
licenses:
|
|
99
|
+
- MIT
|
|
100
|
+
metadata:
|
|
101
|
+
allowed_push_host: https://rubygems.org
|
|
102
|
+
homepage_uri: https://github.com/daddygongon/mk_semi_lattice
|
|
103
|
+
source_code_uri: https://github.com/daddygongon/mk_semi_lattice
|
|
104
|
+
changelog_uri: https://github.com/daddygongon/mk_semi_lattice
|
|
105
|
+
rdoc_options: []
|
|
106
|
+
require_paths:
|
|
107
|
+
- lib
|
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: 3.0.0
|
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
requirements: []
|
|
119
|
+
rubygems_version: 3.6.7
|
|
120
|
+
specification_version: 4
|
|
121
|
+
summary: make semi lattice graph from directory structure
|
|
122
|
+
test_files: []
|