dog 0.2.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/bin/dog +30 -0
- data/lib/dog/map.rb +136 -0
- data/lib/dog/viewer.rb +503 -0
- data/lib/dog.rb +20 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6a288fcd6df7bf73823892332fdb68473ee4c38480d6db0225126d08d6aa32fe
|
4
|
+
data.tar.gz: d451489dfc83de0a0858bf5c374dc7ee82c50e913216fcf547a3c541ffaf1aa6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93100e702f623c5bc573987f0f661300d0dd5acfe297325ffb41277fba6d0401fdf841cef1684e96ae79c33337081d8cc9f73d9715bc374168cb799b01377cc4
|
7
|
+
data.tar.gz: f47071eb9d5710b24461220ca75ae7ca88f0d9af5261e0627b8ccc8e1c42c046851734cab1529cbf592bfaa96c89014a750d3cc4a5eb835b5a43d1e94c04afe9
|
data/bin/dog
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dog'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Usage: dog [options]"
|
8
|
+
|
9
|
+
opts.on("-lTOPIC", "--list=TOPIC", "List the link names in a given topic") do |t|
|
10
|
+
map = Dog::Map.new
|
11
|
+
map.load
|
12
|
+
|
13
|
+
if !map.has_topic?(t)
|
14
|
+
puts "Topic \"#{t}\" not found in map!"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
map.link_names(t).each do |name|
|
19
|
+
puts name
|
20
|
+
end
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-h", "--help", "Prints this help message") do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end.parse!
|
29
|
+
|
30
|
+
Dog::Viewer.new.view
|
data/lib/dog/map.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Dog
|
5
|
+
class Map
|
6
|
+
attr_accessor :topic_name
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@map = {"@home" => []}
|
10
|
+
@topic_name = "@home"
|
11
|
+
end
|
12
|
+
|
13
|
+
def name(topic: @topic_name, index:)
|
14
|
+
@map[topic][index]["name"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def path(topic: @topic_name, index:)
|
18
|
+
@map[topic][index]["path"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def count(topic = @topic_name)
|
22
|
+
@map[topic].length
|
23
|
+
end
|
24
|
+
|
25
|
+
def move_up(topic: @topic_name, index:)
|
26
|
+
if index > 0
|
27
|
+
@map[@topic_name][index],
|
28
|
+
@map[@topic_name][index - 1] =
|
29
|
+
@map[@topic_name][index - 1],
|
30
|
+
@map[@topic_name][index]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def move_down(topic: @topic_name, index:)
|
35
|
+
if index < count(@topic_name) - 1
|
36
|
+
@map[@topic_name][index],
|
37
|
+
@map[@topic_name][index + 1] =
|
38
|
+
@map[@topic_name][index + 1],
|
39
|
+
@map[@topic_name][index]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_topic?(name)
|
44
|
+
@map.has_key?(name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def here
|
48
|
+
@map[@topic_name]
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove_topic(topic = @topic)
|
52
|
+
@map.delete(@topic)
|
53
|
+
end
|
54
|
+
|
55
|
+
def remove_link(topic: @topic_name, name:)
|
56
|
+
here.delete_if do |link|
|
57
|
+
link["name"] == name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def replace(topic: @topic_name, name:, new_name:, new_path:)
|
62
|
+
index = @map[@topic_name].index do |link|
|
63
|
+
link["name"] == name
|
64
|
+
end
|
65
|
+
|
66
|
+
if index
|
67
|
+
here[index] = create_link(new_name, new_path)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def add(topic: @topic_name, name:, path:)
|
72
|
+
@map[@topic_name].push(
|
73
|
+
create_link(name,path)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def navigate( destination )
|
78
|
+
if !@map[destination]
|
79
|
+
@map[destination] = []
|
80
|
+
end
|
81
|
+
|
82
|
+
@topic_name = destination
|
83
|
+
end
|
84
|
+
|
85
|
+
def load
|
86
|
+
begin
|
87
|
+
data = YAML.load_file(MAP_FILENAME)
|
88
|
+
@map = data if data
|
89
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
90
|
+
return false
|
91
|
+
end
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
|
95
|
+
def save
|
96
|
+
File.write(MAP_FILENAME, @map.to_yaml)
|
97
|
+
end
|
98
|
+
|
99
|
+
def [](key)
|
100
|
+
@map[key]
|
101
|
+
end
|
102
|
+
|
103
|
+
def find_incoming_links(destination)
|
104
|
+
links = []
|
105
|
+
@map.each do |key, value|
|
106
|
+
value.each do |item|
|
107
|
+
if item["path"] == destination
|
108
|
+
if key == @topic_name
|
109
|
+
links.push(
|
110
|
+
create_link("#{key} (<<)", key)
|
111
|
+
)
|
112
|
+
else
|
113
|
+
links.push(
|
114
|
+
create_link(key, key)
|
115
|
+
)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
return links
|
121
|
+
end
|
122
|
+
|
123
|
+
def link_names(topic)
|
124
|
+
@map[topic].map{|l| l["name"]}
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def create_link(name, path)
|
130
|
+
{
|
131
|
+
"name" => name,
|
132
|
+
"path" => path
|
133
|
+
}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/dog/viewer.rb
ADDED
@@ -0,0 +1,503 @@
|
|
1
|
+
require 'dog'
|
2
|
+
require "curses"
|
3
|
+
require "uri"
|
4
|
+
require 'digest'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'yaml'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
include Curses
|
10
|
+
|
11
|
+
module Dog
|
12
|
+
class Viewer
|
13
|
+
def initialize
|
14
|
+
@map = Dog::Map.new
|
15
|
+
|
16
|
+
@first_time = @map.load
|
17
|
+
initialize_handlers
|
18
|
+
|
19
|
+
@topic = Window.new(1,cols,0,0)
|
20
|
+
|
21
|
+
colwidth = (cols/2).ceil + 1
|
22
|
+
@left = Window.new(lines/3, colwidth, 1, 0)
|
23
|
+
@right = Window.new(lines/3, colwidth, 1, cols-colwidth)
|
24
|
+
|
25
|
+
@link = Window.new(1,cols,lines/3+1,0)
|
26
|
+
@preview = Window.new(lines - lines/3 - 3,cols,lines/3+2,0)
|
27
|
+
@status = Window.new(1,cols,lines-1,0)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize_handlers
|
31
|
+
if !load_handlers
|
32
|
+
@link_handlers = {
|
33
|
+
".txt$" => {
|
34
|
+
"preview" => "cat %%",
|
35
|
+
"open" => "${EDITOR:-vim} %%"
|
36
|
+
},
|
37
|
+
"/$" => {
|
38
|
+
"preview" => "ls -lah %%",
|
39
|
+
"open" => "${EDITOR:-vim} %%"
|
40
|
+
},
|
41
|
+
"^http" => {
|
42
|
+
"preview" => "echo \"WIP!\"",
|
43
|
+
"open" => "lynx %%"
|
44
|
+
# "preview" => ->(x) {
|
45
|
+
# md5 = Digest::MD5.hexdigest(x)
|
46
|
+
# uri = URI(x)
|
47
|
+
|
48
|
+
# if !Dir.exist?("#{Dir.home}/.dog/cache/#{md5}")
|
49
|
+
# @preview.setpos(0,0)
|
50
|
+
# @preview.addstr("caching html and loading preview...")
|
51
|
+
# @preview.refresh
|
52
|
+
|
53
|
+
# FileUtils.mkdir_p "#{Dir.home}/.dog/cache/#{md5}"
|
54
|
+
# `wget -P #{Dir.home}/.dog/cache/#{md5} -p -q -k #{x} -U "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"`
|
55
|
+
# end
|
56
|
+
|
57
|
+
# @preview.setpos(0,0)
|
58
|
+
# @preview.addstr(`lynx #{Dir.home}/.dog/cache/#{md5}/#{uri.host}/#{uri.path} -dump -force_html`)
|
59
|
+
# },
|
60
|
+
# "open" => ->(x) {
|
61
|
+
# md5 = Digest::MD5.hexdigest(x)
|
62
|
+
# uri = URI(x)
|
63
|
+
# system( "open -a /Applications/Firefox.app #{Dir.home}/.dog/cache/#{md5}/#{uri.host}/#{uri.path}" )
|
64
|
+
# }
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_handlers
|
71
|
+
begin
|
72
|
+
data = YAML.load_file(HANDLERS_FILENAME)
|
73
|
+
@link_handlers = data if data
|
74
|
+
rescue Errno::ENOENT, Errno::ENOTDIR
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
|
80
|
+
def save_handlers
|
81
|
+
File.write(HANDLERS_FILENAME, @link_handlers.to_yaml)
|
82
|
+
end
|
83
|
+
|
84
|
+
def clear_window( window )
|
85
|
+
window.clear
|
86
|
+
if [@topic, @link, @status].include? window
|
87
|
+
window.box(' ', nil, ' ')
|
88
|
+
elsif [@left, @right].include? window
|
89
|
+
window.box(nil, ' ')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def resize
|
94
|
+
colwidth = (cols/2).ceil + 1
|
95
|
+
|
96
|
+
@topic.resize(1, cols)
|
97
|
+
@left.resize(lines/3, colwidth)
|
98
|
+
@right.resize(lines/3, colwidth)
|
99
|
+
|
100
|
+
@link.resize(1, cols)
|
101
|
+
@preview.resize(2*lines/3-2, cols)
|
102
|
+
@status.resize(1, cols)
|
103
|
+
|
104
|
+
@right.move(1, cols-colwidth)
|
105
|
+
|
106
|
+
@link.move(lines/3+1, 0)
|
107
|
+
@preview.move(lines/3+2, 0)
|
108
|
+
@status.move(lines-1, 0)
|
109
|
+
|
110
|
+
@windows.each do |window| window.refresh end
|
111
|
+
navigate( @map.topic_name )
|
112
|
+
end
|
113
|
+
|
114
|
+
def centerx( text = "" )
|
115
|
+
cols/2 - (text&.length || 0)/2
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_menu_item( window, position, text )
|
119
|
+
window.setpos(position, 2)
|
120
|
+
window.attrset( window == @active_window && @active_item == position ? A_STANDOUT : A_NORMAL )
|
121
|
+
window.addstr( text )
|
122
|
+
window.attrset( A_NORMAL )
|
123
|
+
end
|
124
|
+
|
125
|
+
def setup_menu( window, location )
|
126
|
+
clear_window window
|
127
|
+
location&.each_with_index do |link, index|
|
128
|
+
add_menu_item( window, index, link["name"] )
|
129
|
+
end
|
130
|
+
window.refresh
|
131
|
+
end
|
132
|
+
|
133
|
+
def wrap_cursor
|
134
|
+
@active_item = @max_items - 1 if @active_item < 0
|
135
|
+
@active_item = 0 if @active_item >= @max_items
|
136
|
+
end
|
137
|
+
|
138
|
+
def active_link
|
139
|
+
wrap_cursor
|
140
|
+
if @max_items == 0
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
|
144
|
+
if @active_window == @left
|
145
|
+
@incoming[@active_item]["path"]
|
146
|
+
else
|
147
|
+
@map.path(index: @active_item)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def preview_active_file
|
152
|
+
preview_file( active_link )
|
153
|
+
end
|
154
|
+
|
155
|
+
def move_cursor( dir )
|
156
|
+
@active_item += dir
|
157
|
+
|
158
|
+
wrap_cursor
|
159
|
+
|
160
|
+
preview_active_file
|
161
|
+
end
|
162
|
+
|
163
|
+
def set_topic
|
164
|
+
show(@topic, @map.topic_name)
|
165
|
+
end
|
166
|
+
|
167
|
+
def swap_window
|
168
|
+
if @active_window == @left
|
169
|
+
@active_window = @right
|
170
|
+
@max_items = @map.count
|
171
|
+
else
|
172
|
+
if @incoming.length > 0
|
173
|
+
@active_window = @left
|
174
|
+
@max_items = @incoming.length
|
175
|
+
end
|
176
|
+
end
|
177
|
+
wrap_cursor
|
178
|
+
preview_active_file
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_max_items
|
182
|
+
if @active_window == @left
|
183
|
+
@max_items = @incoming.length
|
184
|
+
else
|
185
|
+
@max_items = @map.count
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def navigate( destination )
|
190
|
+
@incoming = @map.find_incoming_links(destination)
|
191
|
+
|
192
|
+
@map.navigate( destination )
|
193
|
+
refresh_display
|
194
|
+
end
|
195
|
+
|
196
|
+
def refresh_display
|
197
|
+
set_topic
|
198
|
+
setup_menu( @left, @incoming )
|
199
|
+
setup_menu( @right, @map.here )
|
200
|
+
|
201
|
+
if ( @incoming.length == 0 )
|
202
|
+
@active_window = @right
|
203
|
+
end
|
204
|
+
set_max_items
|
205
|
+
|
206
|
+
@active_item = 0
|
207
|
+
|
208
|
+
preview_file( active_link )
|
209
|
+
end
|
210
|
+
|
211
|
+
def show( window, text )
|
212
|
+
clear_window window
|
213
|
+
|
214
|
+
if window == @link || window == @topic || window == @status
|
215
|
+
text = " #{text} "
|
216
|
+
window.setpos(0, centerx(text))
|
217
|
+
elsif window == @preview
|
218
|
+
window.setpos(0, 0)
|
219
|
+
else
|
220
|
+
window.setpos(1, 1)
|
221
|
+
end
|
222
|
+
|
223
|
+
window.addstr text
|
224
|
+
window.refresh
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def get_handler( filename )
|
229
|
+
@link_handlers.each do |regex, value|
|
230
|
+
if filename =~ Regexp.new(regex)
|
231
|
+
return value
|
232
|
+
end
|
233
|
+
end
|
234
|
+
return nil
|
235
|
+
end
|
236
|
+
|
237
|
+
def preview_file( filename )
|
238
|
+
if !filename || filename == ""
|
239
|
+
show(@link, "(empty!)")
|
240
|
+
clear_window @preview
|
241
|
+
@preview.refresh
|
242
|
+
return
|
243
|
+
end
|
244
|
+
|
245
|
+
show(@link, filename)
|
246
|
+
|
247
|
+
clear_window @preview
|
248
|
+
|
249
|
+
begin
|
250
|
+
handler = get_handler( filename )
|
251
|
+
if handler
|
252
|
+
@preview.setpos(0,0)
|
253
|
+
@preview.addstr(
|
254
|
+
`#{handler["preview"].gsub('%%',filename)}`
|
255
|
+
)
|
256
|
+
elsif filename[0] == '@'
|
257
|
+
if @map.has_topic?(filename)
|
258
|
+
@preview.setpos(0,0)
|
259
|
+
@preview.addstr(@map.link_names(filename).join("\n"))
|
260
|
+
else
|
261
|
+
@preview.setpos(0,0)
|
262
|
+
@preview.addstr("Topic not found! Open to create.")
|
263
|
+
end
|
264
|
+
else
|
265
|
+
@preview.setpos(0,0)
|
266
|
+
@preview.addstr("No matching preview handler found")
|
267
|
+
end
|
268
|
+
rescue => e
|
269
|
+
@preview.setpos(0,0)
|
270
|
+
@preview.addstr(" Error loading preview for #{filename}!\n#{e}")
|
271
|
+
end
|
272
|
+
|
273
|
+
@preview.refresh
|
274
|
+
end
|
275
|
+
|
276
|
+
def open( filename )
|
277
|
+
begin
|
278
|
+
handler = get_handler( filename )
|
279
|
+
if handler
|
280
|
+
system("#{handler["open"].gsub('%%',filename)}")
|
281
|
+
refresh_display
|
282
|
+
elsif filename[0] == '@'
|
283
|
+
navigate( filename )
|
284
|
+
else
|
285
|
+
@preview.setpos(0,0)
|
286
|
+
@preview.addstr("No matching open handler found")
|
287
|
+
end
|
288
|
+
rescue => e
|
289
|
+
@preview.setpos(0,0)
|
290
|
+
@preview.addstr(" Error opening #{filename}!\n#{e}")
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def menu_loop
|
295
|
+
show(@status, "tab - next field | enter - commit | esc - cancel")
|
296
|
+
curs_set(1)
|
297
|
+
while fch = @preview.getch
|
298
|
+
begin
|
299
|
+
case fch
|
300
|
+
when KEY_RESIZE
|
301
|
+
resize
|
302
|
+
when 9
|
303
|
+
@form.driver(REQ_NEXT_FIELD)
|
304
|
+
when KEY_DOWN
|
305
|
+
@form.driver(REQ_NEXT_FIELD)
|
306
|
+
when 353
|
307
|
+
@form.driver(REQ_PREV_FIELD)
|
308
|
+
when KEY_UP
|
309
|
+
@form.driver(REQ_PREV_FIELD)
|
310
|
+
when 10
|
311
|
+
@form.driver(REQ_VALIDATION)
|
312
|
+
@form.unpost
|
313
|
+
|
314
|
+
if @editing
|
315
|
+
@map.replace(
|
316
|
+
name: @map.name(index: @active_item),
|
317
|
+
new_name: @name_field.buffer(0).strip,
|
318
|
+
new_path: @link_field.buffer(0).strip
|
319
|
+
)
|
320
|
+
else
|
321
|
+
@map.add(
|
322
|
+
name: @name_field.buffer(0).strip,
|
323
|
+
path: @link_field.buffer(0).strip
|
324
|
+
)
|
325
|
+
end
|
326
|
+
refresh_display
|
327
|
+
show(@status, "done")
|
328
|
+
break
|
329
|
+
when 127
|
330
|
+
@form.driver(REQ_DEL_PREV)
|
331
|
+
when KEY_LEFT
|
332
|
+
@form.driver(REQ_PREV_CHAR)
|
333
|
+
when KEY_RIGHT
|
334
|
+
@form.driver(REQ_NEXT_CHAR)
|
335
|
+
when 27
|
336
|
+
@form.unpost
|
337
|
+
refresh_display
|
338
|
+
show(@status, "cancelled")
|
339
|
+
break
|
340
|
+
else
|
341
|
+
fch.to_s.each_char do |letter|
|
342
|
+
@form.driver(letter)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
rescue Curses::RequestDeniedError
|
346
|
+
end
|
347
|
+
end
|
348
|
+
curs_set(0)
|
349
|
+
end
|
350
|
+
|
351
|
+
|
352
|
+
def view
|
353
|
+
init_screen
|
354
|
+
start_color
|
355
|
+
curs_set(0)
|
356
|
+
noecho
|
357
|
+
cbreak
|
358
|
+
|
359
|
+
@preview.keypad(true)
|
360
|
+
|
361
|
+
@windows = [@topic, @left, @right, @link, @preview, @status]
|
362
|
+
@windows.each do |window|
|
363
|
+
clear_window window
|
364
|
+
end
|
365
|
+
|
366
|
+
@active_window = @right
|
367
|
+
@active_item = 0
|
368
|
+
@max_items = 0
|
369
|
+
@incoming = []
|
370
|
+
|
371
|
+
@name_field = Field.new( 1, cols - 4, 2, 2, 0, 0 )
|
372
|
+
@name_field.set_back(A_UNDERLINE)
|
373
|
+
@name_field.opts_off(O_BLANK | O_STATIC)
|
374
|
+
@link_field = Field.new( 1, cols - 4, 5, 2, 0, 0 )
|
375
|
+
@link_field.set_back(A_UNDERLINE)
|
376
|
+
@link_field.opts_off(O_BLANK | O_STATIC)
|
377
|
+
|
378
|
+
@form = Form.new( [@name_field, @link_field] )
|
379
|
+
@form.set_win @preview
|
380
|
+
|
381
|
+
@editing = false
|
382
|
+
|
383
|
+
|
384
|
+
refresh_display
|
385
|
+
show(@status, "woof! - press ? for help")
|
386
|
+
|
387
|
+
while ch = @right.getch
|
388
|
+
show(@status, "woof! - press ? for help")
|
389
|
+
|
390
|
+
case ch
|
391
|
+
when KEY_RESIZE
|
392
|
+
resize
|
393
|
+
when 's'
|
394
|
+
@map.save
|
395
|
+
save_handlers
|
396
|
+
show(@status, "saved!")
|
397
|
+
when 'J'
|
398
|
+
if @active_window == @right
|
399
|
+
@map.move_down(index: @active_item)
|
400
|
+
move_cursor( 1 )
|
401
|
+
end
|
402
|
+
when 'K'
|
403
|
+
if @active_window == @right
|
404
|
+
@map.move_up(index: @active_item)
|
405
|
+
move_cursor( -1 )
|
406
|
+
end
|
407
|
+
when 'j'
|
408
|
+
move_cursor( 1 )
|
409
|
+
when 'k'
|
410
|
+
move_cursor( -1 )
|
411
|
+
when 'h'
|
412
|
+
swap_window
|
413
|
+
when 'l'
|
414
|
+
swap_window
|
415
|
+
when ' '
|
416
|
+
open(active_link)
|
417
|
+
when '?'
|
418
|
+
show(@preview, HELP_TEXT)
|
419
|
+
when 'q'
|
420
|
+
break
|
421
|
+
when 'n'
|
422
|
+
clear_window @preview
|
423
|
+
@name_field.set_buffer(0, "")
|
424
|
+
@link_field.set_buffer(0, "")
|
425
|
+
@form.post
|
426
|
+
@preview.setpos(1,0)
|
427
|
+
@preview.addstr("name:")
|
428
|
+
@preview.setpos(4,0)
|
429
|
+
@preview.addstr("link:")
|
430
|
+
@preview.refresh
|
431
|
+
show(@link, "(new link)")
|
432
|
+
|
433
|
+
@editing = false
|
434
|
+
|
435
|
+
@form.driver(REQ_FIRST_FIELD)
|
436
|
+
|
437
|
+
menu_loop
|
438
|
+
when 'e'
|
439
|
+
if @active_window == @right
|
440
|
+
clear_window @preview
|
441
|
+
@name_field.set_buffer(0, @map.name(index: @active_item))
|
442
|
+
@link_field.set_buffer(0, @map.path(index: @active_item))
|
443
|
+
@form.post
|
444
|
+
@preview.setpos(1,0)
|
445
|
+
@preview.addstr("name:")
|
446
|
+
@preview.setpos(4,0)
|
447
|
+
@preview.addstr("link:")
|
448
|
+
@preview.refresh
|
449
|
+
show(@link, "(edit link)")
|
450
|
+
|
451
|
+
@editing = true
|
452
|
+
|
453
|
+
@form.driver(REQ_FIRST_FIELD)
|
454
|
+
|
455
|
+
menu_loop
|
456
|
+
end
|
457
|
+
when 'd'
|
458
|
+
if @active_window == @right
|
459
|
+
clear_window @preview
|
460
|
+
@preview.setpos(1,0)
|
461
|
+
@preview.addstr("really delete link \"#{@map.name(index: @active_item)}\"?")
|
462
|
+
@preview.setpos(3,0)
|
463
|
+
@preview.addstr("y / n")
|
464
|
+
@preview.refresh
|
465
|
+
if @preview.getch == 'y'
|
466
|
+
if active_link[0] == "@" && @map.find_incoming_links( active_link ).length == 1
|
467
|
+
target = @map.path(index: @active_item)
|
468
|
+
clear_window @preview
|
469
|
+
@preview.setpos(1,0)
|
470
|
+
@preview.addstr("this change strands the topic \"#{target}\".")
|
471
|
+
@preview.setpos(2,0)
|
472
|
+
@preview.addstr("do you want to delete that topic, too?")
|
473
|
+
@preview.setpos(3,0)
|
474
|
+
@preview.addstr("y / n")
|
475
|
+
@preview.refresh
|
476
|
+
|
477
|
+
if @preview.getch == 'y'
|
478
|
+
@map.remove_topic(target)
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
@map.remove_link(name: @map.name(index: @active_item))
|
483
|
+
end
|
484
|
+
@max_items = @map.here.length
|
485
|
+
wrap_cursor
|
486
|
+
preview_active_file
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
if @active_window == @left
|
491
|
+
setup_menu( @right, @map.here )
|
492
|
+
setup_menu( @left, @incoming )
|
493
|
+
else
|
494
|
+
setup_menu( @left, @incoming )
|
495
|
+
setup_menu( @right, @map.here )
|
496
|
+
end
|
497
|
+
@status.refresh
|
498
|
+
@active_window.refresh
|
499
|
+
end
|
500
|
+
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
data/lib/dog.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'dog/viewer'
|
2
|
+
require 'dog/map'
|
3
|
+
|
4
|
+
module Dog
|
5
|
+
MAP_FILENAME = "#{Dir.home}/.dog/map.yaml"
|
6
|
+
HANDLERS_FILENAME = "#{Dir.home}/.dog/handlers.yaml"
|
7
|
+
WELCOME_TEXT = "welcome to dog! this is your home topic. you can create a new link by pressing [n].\n\n try making a link that points to \"@newtopic\" to create a new topic!"
|
8
|
+
HELP_TEXT = <<~EOS
|
9
|
+
hjkl - move cursor
|
10
|
+
space - open link
|
11
|
+
n - new link
|
12
|
+
e - edit link
|
13
|
+
d - delete link
|
14
|
+
K - move link up within topic
|
15
|
+
J - move link down within topic
|
16
|
+
s - save map
|
17
|
+
q - quit
|
18
|
+
? - show this help!
|
19
|
+
EOS
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dog
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- scout
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-04-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Bookmark and organize local and remote files
|
14
|
+
email: scout@bittybunny.com
|
15
|
+
executables:
|
16
|
+
- dog
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/dog
|
21
|
+
- lib/dog.rb
|
22
|
+
- lib/dog/map.rb
|
23
|
+
- lib/dog/viewer.rb
|
24
|
+
homepage: https://rubygems.org/gems/dog
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubygems_version: 3.4.10
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Digital OrGanizer
|
47
|
+
test_files: []
|