fled 0.0.2 → 0.0.3
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.
- data/README.md +459 -89
- data/bin/fled +341 -53
- data/lib/dtc/utils/exec.rb +13 -2
- data/lib/dtc/utils/interactive_edit.rb +10 -0
- data/lib/dtc/utils/meta.rb +47 -0
- data/lib/dtc/utils/text/html.rb +107 -0
- data/lib/dtc/utils/text/line_writer.rb +70 -0
- data/lib/dtc/utils/text.rb +23 -0
- data/lib/dtc/utils/visitor/dsl.rb +98 -0
- data/lib/dtc/utils/visitor/folder.rb +87 -0
- data/lib/dtc/utils/visitor.rb +272 -0
- data/lib/dtc/utils.rb +3 -1
- data/lib/fled/file_listing.rb +35 -62
- data/lib/fled/file_listing_builder.rb +43 -0
- data/lib/fled.rb +18 -5
- data/tests/helper.rb +14 -26
- data/tests/readme.rb +139 -85
- metadata +9 -3
- data/lib/dtc/utils/dsldsl.rb +0 -259
- data/lib/dtc/utils/file_visitor.rb +0 -79
data/lib/fled/file_listing.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
module FlEd
|
2
|
+
# In memory tree structure for storing
|
3
|
+
# a file-system
|
2
4
|
class FileListing
|
3
5
|
def initialize
|
4
6
|
@objects_by_id = {}
|
5
7
|
@objects = []
|
8
|
+
@errors = []
|
6
9
|
end
|
10
|
+
attr_accessor :errors
|
7
11
|
RELATION_KEYS = [:parent]
|
8
12
|
def dup
|
9
13
|
result = self.class.new
|
@@ -54,7 +58,7 @@ module FlEd
|
|
54
58
|
previous_indent = nil
|
55
59
|
previous = nil
|
56
60
|
stack = []
|
57
|
-
listing.split("\n").
|
61
|
+
listing.split("\n").each_with_index do |line, line_number|
|
58
62
|
next if line.strip.empty?
|
59
63
|
raise RuntimeError, "Unparsable line #{line.inspect}" unless line =~ /^((?: )*)(.*?)(?::(\d+))?\r?$/
|
60
64
|
indent = $1
|
@@ -62,7 +66,15 @@ module FlEd
|
|
62
66
|
if (dir = name[-1..-1] == "/")
|
63
67
|
name = name[0..-2]
|
64
68
|
end
|
65
|
-
current =
|
69
|
+
current = nil
|
70
|
+
begin
|
71
|
+
current = objects.add($3, :name => name, :line => "#{$1}#{$2}")
|
72
|
+
rescue Exception => e
|
73
|
+
(objects.errors ||= []) << [:fail,
|
74
|
+
:duplicate_uid, {:name => name, :line_number => line_number + 1}
|
75
|
+
]
|
76
|
+
end
|
77
|
+
next unless current
|
66
78
|
current[:dir] = true if dir
|
67
79
|
next if name.strip == "" # Ignore indent when there is no name - element will be deleted, parent isnt used
|
68
80
|
if previous_indent && previous_indent != indent
|
@@ -72,6 +84,7 @@ module FlEd
|
|
72
84
|
stack.pop
|
73
85
|
end
|
74
86
|
end
|
87
|
+
current[:line_number] = line_number + 1
|
75
88
|
current[:parent] = stack.last if stack.count > 0
|
76
89
|
previous = current
|
77
90
|
previous_indent = indent
|
@@ -80,8 +93,21 @@ module FlEd
|
|
80
93
|
end
|
81
94
|
end
|
82
95
|
class FileListing # Shell operation list builder
|
96
|
+
# Generate a list of operations that
|
97
|
+
# would transform the `source_listing`
|
98
|
+
# into the receiver.
|
99
|
+
#
|
100
|
+
# Result is an array with each entry of
|
101
|
+
# the format:
|
102
|
+
#
|
103
|
+
# - `[:fail, reason_symbol, target]`
|
104
|
+
# - `[:warn, reason_symbol, target]`
|
105
|
+
# - `[:mk, [path components]]`
|
106
|
+
# - `[:moved, [source path components], [dest path components]]`
|
107
|
+
# - `[:renamed, [source path components], new name]`
|
108
|
+
# - `[:rm, [path components], source_object]`
|
83
109
|
def operations_from! source_listing
|
84
|
-
|
110
|
+
op_errors = []
|
85
111
|
operations = []
|
86
112
|
pending_renames = []
|
87
113
|
running_source = source_listing.dup
|
@@ -100,7 +126,7 @@ module FlEd
|
|
100
126
|
source = running_source[target[:uid]]
|
101
127
|
if !(target[:source] = source)
|
102
128
|
target[:error] = true
|
103
|
-
|
129
|
+
op_errors += [[:fail, :no_such_uid, target]]
|
104
130
|
next
|
105
131
|
end
|
106
132
|
next if target[:name] == ""
|
@@ -148,7 +174,8 @@ module FlEd
|
|
148
174
|
new_name = op[2]
|
149
175
|
existing_names = running_source.children_of((target[:parent] || {})[:uid]).map { |o| o[:name] }
|
150
176
|
if existing_names.any? { |n| n.casecmp(new_name) == 0 }
|
151
|
-
|
177
|
+
op_errors += [[:warn, :would_overwrite, target,
|
178
|
+
running_source.path_of(target[:parent]).map { |o| o[:name] } + [new_name]]]
|
152
179
|
else
|
153
180
|
operations << [:renamed,
|
154
181
|
running_source.path_of(target).map { |o| o[:name] },
|
@@ -159,10 +186,11 @@ module FlEd
|
|
159
186
|
end
|
160
187
|
self.depth_first do |target, path|
|
161
188
|
if target[:name] == ""
|
162
|
-
|
189
|
+
operation = target[:source][:dir] ? :rmdir : :rm
|
190
|
+
operations << [operation, running_source.path_of(target[:source]).map { |o| o[:name] }, target[:source]]
|
163
191
|
end
|
164
192
|
end
|
165
|
-
errors + operations
|
193
|
+
errors + op_errors + operations
|
166
194
|
end
|
167
195
|
def has_child? parent, child
|
168
196
|
while child = child[:parent]
|
@@ -207,59 +235,4 @@ module FlEd
|
|
207
235
|
to_browse.each { |child| breadth_first child, path + [child], &block }
|
208
236
|
end
|
209
237
|
end
|
210
|
-
class ListingBuilder < DTC::Utils::FileVisitor
|
211
|
-
attr_accessor :listing
|
212
|
-
def initialize listing = FileListing.new
|
213
|
-
@listing = listing
|
214
|
-
end
|
215
|
-
def add_object path, dir
|
216
|
-
uid = next_uid
|
217
|
-
name = File.basename(path)
|
218
|
-
object = @listing.add(uid,
|
219
|
-
:path => path,
|
220
|
-
:name => File.basename(path),
|
221
|
-
:parent => @object_stack.last,
|
222
|
-
:line => "#{" " * self.depth}#{name}#{dir ? "/" : ""}"
|
223
|
-
)
|
224
|
-
object[:dir] = true if dir
|
225
|
-
object
|
226
|
-
end
|
227
|
-
def enter_folder dir
|
228
|
-
depth = self.depth
|
229
|
-
if self.depth == 0
|
230
|
-
@object_stack = []
|
231
|
-
else
|
232
|
-
@object_stack.push add_object(dir, true)
|
233
|
-
end
|
234
|
-
super
|
235
|
-
end
|
236
|
-
def visit_file name, full_path
|
237
|
-
add_object full_path, false
|
238
|
-
super
|
239
|
-
end
|
240
|
-
def leave_folder
|
241
|
-
@object_stack.pop
|
242
|
-
super
|
243
|
-
end
|
244
|
-
protected
|
245
|
-
def next_uid
|
246
|
-
@listing.count
|
247
|
-
end
|
248
|
-
def source_path source
|
249
|
-
res = []
|
250
|
-
while source
|
251
|
-
res.unshift target[:name]
|
252
|
-
target = target[:parent]
|
253
|
-
end
|
254
|
-
File.join(res)
|
255
|
-
end
|
256
|
-
def target_path target
|
257
|
-
res = []
|
258
|
-
while target
|
259
|
-
res.unshift target[:name]
|
260
|
-
target = target[:parent]
|
261
|
-
end
|
262
|
-
File.join(res)
|
263
|
-
end
|
264
|
-
end
|
265
238
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module FlEd
|
2
|
+
class FileListingBuilder
|
3
|
+
attr_accessor :listing
|
4
|
+
def initialize listing = FileListing.new
|
5
|
+
@listing = listing
|
6
|
+
@folders = []
|
7
|
+
end
|
8
|
+
def add_object path, dir
|
9
|
+
uid = next_uid
|
10
|
+
name = File.basename(path)
|
11
|
+
object = @listing.add(uid,
|
12
|
+
:path => path,
|
13
|
+
:name => File.basename(path),
|
14
|
+
:parent => @object_stack.last,
|
15
|
+
:line => "#{" " * depth}#{name}#{dir ? "/" : ""}"
|
16
|
+
)
|
17
|
+
object[:dir] = true if dir
|
18
|
+
object
|
19
|
+
end
|
20
|
+
def depth ; @folders.count ; end
|
21
|
+
def full_path *args ; File.join((@folders || []) + args) ; end
|
22
|
+
def enter dir
|
23
|
+
if depth.zero?
|
24
|
+
@object_stack = []
|
25
|
+
else
|
26
|
+
@object_stack.push add_object(dir, true)
|
27
|
+
end
|
28
|
+
@folders << dir
|
29
|
+
true
|
30
|
+
end
|
31
|
+
def add name, full_path
|
32
|
+
add_object full_path, false
|
33
|
+
end
|
34
|
+
def leave
|
35
|
+
@object_stack.pop
|
36
|
+
@folders.pop
|
37
|
+
end
|
38
|
+
protected
|
39
|
+
def next_uid
|
40
|
+
@listing.count
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/fled.rb
CHANGED
@@ -3,9 +3,12 @@ require 'shellwords'
|
|
3
3
|
|
4
4
|
module FlEd
|
5
5
|
require 'fled/file_listing'
|
6
|
+
require 'fled/file_listing_builder'
|
6
7
|
|
7
|
-
VERSION = '0.0.
|
8
|
+
VERSION = '0.0.3'
|
8
9
|
|
10
|
+
# Convert file listing operation list
|
11
|
+
# to bash-script friendly script
|
9
12
|
def self.operation_list_to_bash ops
|
10
13
|
ops = ops.map do |op|
|
11
14
|
case op.first
|
@@ -15,18 +18,28 @@ module FlEd
|
|
15
18
|
[:mv, File.join(op[1]), File.join(op[2])]
|
16
19
|
when :renamed
|
17
20
|
[:mv, File.join(op[1]), File.join((op[1].empty? ? [] : op[1][0..-2]) + [op[2]])]
|
18
|
-
when :rm
|
19
|
-
[op
|
21
|
+
when :rm, :rmdir
|
22
|
+
[op.first , File.join(op[1])]
|
20
23
|
else
|
21
24
|
op
|
22
25
|
end
|
23
26
|
end
|
24
27
|
warnings, operations = *ops.partition { |e| e.first == :warn }
|
28
|
+
errors, operations = *operations.partition { |e| e.first == :fail }
|
25
29
|
result = []
|
30
|
+
unless errors.empty?
|
31
|
+
result += ["# Error:"]
|
32
|
+
errors.each do |error|
|
33
|
+
line = error[2][:line_number]
|
34
|
+
result += ["# - line #{line}: #{error[1]}"]
|
35
|
+
end
|
36
|
+
result += ['', 'exit 1 # There are errors to check first !', '']
|
37
|
+
end
|
26
38
|
unless warnings.empty?
|
27
|
-
result
|
39
|
+
result += ["# Warning:"]
|
28
40
|
warnings.each do |warning|
|
29
|
-
|
41
|
+
line = warning[2][:line_number]
|
42
|
+
result += ["# - line #{line}: #{warning[1]}: #{File.join(warning[3])}"]
|
30
43
|
end
|
31
44
|
result += ['', 'exit 1 # There are warnings to check first !', '']
|
32
45
|
end
|
data/tests/helper.rb
CHANGED
@@ -2,45 +2,33 @@
|
|
2
2
|
$:.unshift File.join(File.dirname(__FILE__),'../lib')
|
3
3
|
require 'fled'
|
4
4
|
|
5
|
-
class
|
6
|
-
def enter_folder dir
|
7
|
-
depth = self.depth
|
8
|
-
puts (" " * depth) + (depth > 0 ? File.basename(dir) : dir)
|
9
|
-
super
|
10
|
-
end
|
11
|
-
def visit_file name, full_path
|
12
|
-
puts (" " * depth) + name
|
13
|
-
super
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class TestListingBuilder < FlEd::ListingBuilder
|
5
|
+
class TestListingBuilder < FlEd::FileListingBuilder
|
18
6
|
def next_uid
|
19
7
|
@uid
|
20
8
|
end
|
21
|
-
def
|
9
|
+
def enter dir, uid = nil
|
22
10
|
@uid = uid
|
23
|
-
super dir
|
11
|
+
super dir.to_s
|
24
12
|
end
|
25
|
-
def
|
13
|
+
def add name, uid
|
26
14
|
@uid = uid
|
27
|
-
super name,
|
15
|
+
super name, full_path(name.to_s)
|
28
16
|
end
|
29
17
|
end
|
30
18
|
|
31
19
|
class TestFS
|
32
20
|
def initialize &block
|
33
|
-
@root = DTC::Utils::
|
21
|
+
@root = DTC::Utils::Visitor::DSL::accept(DTC::Utils::Visitor::HashBuilder, &block).root
|
34
22
|
end
|
35
23
|
def receive visitor, root = @root
|
36
24
|
root.each_pair do |name, val|
|
37
|
-
next if name
|
25
|
+
next if name.nil?
|
38
26
|
if val.is_a?(Array)
|
39
|
-
visitor.
|
27
|
+
visitor.add name, val[0]
|
40
28
|
elsif val.is_a?(Hash)
|
41
|
-
if visitor.
|
29
|
+
if visitor.enter(name, val[nil][0])
|
42
30
|
receive(visitor, val)
|
43
|
-
visitor.
|
31
|
+
visitor.leave
|
44
32
|
end
|
45
33
|
else
|
46
34
|
raise RuntimeError, "Unknown value #{val.inspect}"
|
@@ -49,9 +37,9 @@ class TestFS
|
|
49
37
|
end
|
50
38
|
def new_builder
|
51
39
|
builder = TestListingBuilder.new
|
52
|
-
builder.
|
40
|
+
builder.enter("$")
|
53
41
|
receive builder
|
54
|
-
builder.
|
42
|
+
builder.leave
|
55
43
|
builder
|
56
44
|
end
|
57
45
|
def new_listing
|
@@ -71,8 +59,8 @@ class TestFS
|
|
71
59
|
[:mv, File.join(op[1]), File.join(op[2])]
|
72
60
|
when :renamed
|
73
61
|
[:mv, File.join(op[1]), File.join((op[1].empty? ? [] : op[1][0..-2]) + [op[2]])]
|
74
|
-
when :rm
|
75
|
-
[op
|
62
|
+
when :rm, :rmdir
|
63
|
+
[op.first, File.join(op[1])]
|
76
64
|
else
|
77
65
|
op
|
78
66
|
end
|
data/tests/readme.rb
CHANGED
@@ -4,75 +4,124 @@ else
|
|
4
4
|
require File.join(File.dirname(__FILE__), 'helper')
|
5
5
|
end
|
6
6
|
|
7
|
-
class
|
8
|
-
def
|
9
|
-
|
7
|
+
class MarkdownDumbLineWriter < DTC::Utils::Text::LineWriter
|
8
|
+
def nl ; push_raw "" ; end
|
9
|
+
def text *str
|
10
|
+
push DTC::Utils::Text.lines_without_indent(split_lines(*str))
|
10
11
|
end
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
if exception && @result.length > 1 &&
|
16
|
-
(@result[-2] || "")[0..exception.length - 1] == exception
|
17
|
-
@result.pop
|
18
|
-
end
|
19
|
-
end
|
12
|
+
def para *str
|
13
|
+
enter_mode nil
|
14
|
+
text *str
|
20
15
|
end
|
21
|
-
def << str ; @result += str.is_a?(Array) ? str : [str] ; end
|
22
|
-
def nl ; @result += [""] ; end
|
23
16
|
def title str, depth = 2, *args
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
args.each { |a| text a }
|
17
|
+
enter_mode :title
|
18
|
+
push_raw "#{"#" * depth} #{str}"
|
19
|
+
para *args unless args.empty?
|
28
20
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
self << reindent(str, indent)
|
35
|
-
nl
|
36
|
-
end
|
37
|
-
def reindent str, indent = ""
|
38
|
-
lines = str.split(/\r?\n/).map
|
39
|
-
lines.shift if lines.first.empty?
|
40
|
-
min_spaces = lines.map { |l| l =~ /^( +)/ ? $1.length : nil }.select{ |e| e }.min || 0
|
41
|
-
lines.map { |l| indent + ((min_spaces == 0 ? l : l[min_spaces..-1]) || "") }
|
21
|
+
# h1-5
|
22
|
+
5.times do |i|
|
23
|
+
define_method "h#{i + 1}".to_sym do |str, *a|
|
24
|
+
title str, i + 1, *a
|
25
|
+
end
|
42
26
|
end
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
ensure_clear "-"
|
47
|
-
self << reindent(str, "- ")
|
48
|
-
nl
|
27
|
+
def html *str ;
|
28
|
+
enter_mode :html
|
29
|
+
push_raw *str
|
49
30
|
end
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
31
|
+
def strong str ; para "**#{str}**" ; end
|
32
|
+
def em str ; para "*#{str}*" ; end
|
33
|
+
({
|
34
|
+
:li => "- ",
|
35
|
+
:pre => " ",
|
36
|
+
:quote => "> ",
|
37
|
+
}).each_pair do |method, indentation|
|
38
|
+
define_method method do |*str, &blk|
|
39
|
+
enter_mode method
|
40
|
+
push_indent(indentation) {
|
41
|
+
push_unindented_and_yield str, &blk
|
42
|
+
}
|
58
43
|
end
|
59
44
|
end
|
60
|
-
|
45
|
+
protected
|
46
|
+
def enter_mode mode
|
47
|
+
nl if lines.last != "" && @mode != mode
|
48
|
+
@mode = mode
|
49
|
+
end
|
50
|
+
def split_lines *lines
|
51
|
+
result = lines.flatten.map { |l| DTC::Utils::Text::lines(l) }.flatten
|
52
|
+
result.shift while result.first == ""
|
53
|
+
result.pop while (result.last || "").strip == ""
|
54
|
+
result
|
55
|
+
end
|
56
|
+
def push_unindented_and_yield lines
|
57
|
+
push(DTC::Utils::Text.lines_without_indent(split_lines(lines))) if lines
|
58
|
+
yield if block_given?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class MarkdownDumbLineWriter
|
63
|
+
include DTC::Utils::Visitor::AcceptAsFlatMethodCalls
|
61
64
|
end
|
62
65
|
|
63
|
-
class
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
class MarkdownAndHTMLVisitor < DTC::Utils::Visitor::Switcher
|
67
|
+
def initialize
|
68
|
+
@writer = MarkdownDumbLineWriter.new
|
69
|
+
super @writer
|
70
|
+
end
|
71
|
+
def to_s
|
72
|
+
@writer.to_s
|
73
|
+
end
|
74
|
+
protected
|
75
|
+
def visitor_for_subtree sym, *args
|
76
|
+
if @visitor_stack.count == 1 && sym == :html
|
77
|
+
DTC::Utils::Text::HTML::Writer.new
|
78
|
+
else
|
79
|
+
nil
|
70
80
|
end
|
71
|
-
|
81
|
+
end
|
82
|
+
def visitor_left_subtree visitor, *args
|
83
|
+
add :html, visitor.to_s
|
72
84
|
end
|
73
85
|
end
|
74
86
|
|
75
|
-
readme
|
87
|
+
def readme &blk
|
88
|
+
puts DTC::Utils::Visitor::DSL::accept(MarkdownAndHTMLVisitor, &blk).to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
readme do
|
92
|
+
def show_example listing, example, operations
|
93
|
+
html {
|
94
|
+
table {
|
95
|
+
tr {
|
96
|
+
th { em "Original listing" }
|
97
|
+
th { em "Edited listing" }
|
98
|
+
}
|
99
|
+
tr {
|
100
|
+
td { pre listing }
|
101
|
+
td { pre(DTC::Utils::Text.lines_without_indent example) }
|
102
|
+
}
|
103
|
+
tr {
|
104
|
+
th(:colspan => 2) { em "Generates the script:" }
|
105
|
+
}
|
106
|
+
tr {
|
107
|
+
td(:colspan => 2) {
|
108
|
+
if operations.empty?
|
109
|
+
em "No operation"
|
110
|
+
else
|
111
|
+
ul {
|
112
|
+
operations.each { |op| li { code op } }
|
113
|
+
}
|
114
|
+
end
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
end
|
120
|
+
def run_example fs, example
|
121
|
+
ops = fs.commands_if_edited_as(example)
|
122
|
+
show_example fs.new_listing.to_s, example, ops
|
123
|
+
end
|
124
|
+
|
76
125
|
h1 "FlEd", '`fled` lets you organise your files and folders in your favourite editor'
|
77
126
|
|
78
127
|
h2 "Introduction", <<-MD
|
@@ -118,8 +167,8 @@ readme = ExampleDSLWriter.run do
|
|
118
167
|
["Edit current folder using options", "fled --load fled.config.yaml"],
|
119
168
|
["Add options to a command (`mkdir`, `mv`, `rm` or `rmdir`)", "fled | sed 's/^mv/mv -i/'"],
|
120
169
|
].each do |t, c|
|
121
|
-
|
122
|
-
|
170
|
+
para t
|
171
|
+
pre c
|
123
172
|
end
|
124
173
|
|
125
174
|
h2 "Listing Format"
|
@@ -133,29 +182,30 @@ readme = ExampleDSLWriter.run do
|
|
133
182
|
}
|
134
183
|
end
|
135
184
|
|
136
|
-
|
185
|
+
pre fs.new_listing.to_s
|
137
186
|
|
138
|
-
|
139
|
-
Each line of the listing is in the format
|
187
|
+
para <<-MD
|
188
|
+
Each line of the listing is in the format `[indentation] name: uid`
|
140
189
|
|
141
190
|
- The *indentation* must consist of only spaces, and is used to indicate the parent folder
|
142
191
|
- The *name* must not use colons (`:`). If it is cleared, it is assumed the file/folder is to be deleted
|
192
|
+
The *name* has a `/` appended if it is a directory.
|
143
193
|
- The *uid* is used by FlEd to recognise the original of the edited line. Do not assume a *uid* does not
|
144
|
-
change between runs. It is valid only
|
194
|
+
change between runs. It is valid only for the current run. Spaces before the *uid* are only cosmetic.
|
145
195
|
MD
|
146
196
|
|
147
197
|
h2 "Operations"
|
148
198
|
|
149
199
|
h3 "Creating a new folder", 'Add a new line (therefore with no uid):'
|
150
|
-
|
200
|
+
run_example fs, <<-EXAMPLE
|
151
201
|
folder/ :0
|
152
202
|
new_folder
|
153
203
|
folder_two/ :2
|
154
204
|
EXAMPLE
|
155
205
|
|
156
206
|
h3 "Moving"
|
157
|
-
|
158
|
-
|
207
|
+
para 'Change the indentation and/or line order to change the parent of a file or folder:'
|
208
|
+
run_example fs, <<-EXAMPLE
|
159
209
|
folder/ :0
|
160
210
|
folder_two/ :2
|
161
211
|
file_one :1
|
@@ -164,17 +214,16 @@ readme = ExampleDSLWriter.run do
|
|
164
214
|
em 'Moving an item below itself or its children is not recommended, as the listing may not be exhaustive'
|
165
215
|
|
166
216
|
h3 "Renaming"
|
167
|
-
|
168
|
-
|
217
|
+
para 'Edit the name while preserving the uid to rename the item'
|
218
|
+
run_example fs, <<-EXAMPLE
|
169
219
|
folder_renamed/ :0
|
170
220
|
file_one :1
|
171
221
|
folder_two/ :2
|
172
222
|
file_changed :3
|
173
223
|
EXAMPLE
|
174
|
-
text '*Swapping file names may not work in cases where the generated intermediary file exists but was not included in the listing*'
|
175
224
|
|
176
225
|
h3 "Deleting", 'Clear a name but leave the uid to delete that item'
|
177
|
-
|
226
|
+
run_example fs, <<-EXAMPLE
|
178
227
|
folder_renamed/ :0
|
179
228
|
:1
|
180
229
|
:2
|
@@ -182,31 +231,29 @@ readme = ExampleDSLWriter.run do
|
|
182
231
|
EXAMPLE
|
183
232
|
|
184
233
|
h3 "No-op"
|
185
|
-
|
186
|
-
|
234
|
+
para 'If a line (and all child-lines) is removed from the listing, it will have no operation.'
|
235
|
+
run_example fs, <<-EXAMPLE
|
187
236
|
folder/ :0
|
188
237
|
EXAMPLE
|
189
|
-
|
190
|
-
nl
|
191
|
-
text '*Note that removing a folder without removing its children will move its children:*'
|
238
|
+
para '*Note that removing a folder without removing its children will move its children:*'
|
192
239
|
|
193
|
-
|
240
|
+
run_example fs, <<-EXAMPLE
|
194
241
|
folder/ :0
|
195
242
|
file_one :1
|
196
243
|
file_three :3
|
197
244
|
EXAMPLE
|
198
245
|
|
199
246
|
nl
|
200
|
-
|
247
|
+
para "If an indent is forgotten:"
|
201
248
|
|
202
|
-
|
249
|
+
run_example fs, <<-EXAMPLE
|
203
250
|
folder/ :0
|
204
251
|
file_one :1
|
205
252
|
file_three :3
|
206
253
|
EXAMPLE
|
207
254
|
|
208
255
|
h3 "All together"
|
209
|
-
|
256
|
+
run_example fs, <<-EXAMPLE
|
210
257
|
folder_new/ :0
|
211
258
|
new_folder/
|
212
259
|
first :1
|
@@ -224,13 +271,14 @@ readme = ExampleDSLWriter.run do
|
|
224
271
|
file_two(2)
|
225
272
|
}
|
226
273
|
end
|
227
|
-
|
228
|
-
|
229
|
-
|
274
|
+
pre fs.new_listing.to_s
|
275
|
+
para "When applying"
|
276
|
+
run_example fs, <<-EXAMPLE
|
230
277
|
folder/ :0
|
231
278
|
file_two :1
|
232
279
|
file_one :2
|
233
280
|
EXAMPLE
|
281
|
+
para '*Swapping file names may not work in cases where the generated intermediary file exists but was not included in the listing*'
|
234
282
|
|
235
283
|
h3 "Tree swapping"
|
236
284
|
fs = TestFS.new do
|
@@ -242,9 +290,9 @@ readme = ExampleDSLWriter.run do
|
|
242
290
|
}
|
243
291
|
}
|
244
292
|
end
|
245
|
-
|
246
|
-
|
247
|
-
|
293
|
+
pre fs.new_listing.to_s
|
294
|
+
para "When applying"
|
295
|
+
run_example fs, <<-EXAMPLE
|
248
296
|
sub_sub_folder/ :2
|
249
297
|
sub_folder/ :1
|
250
298
|
folder/ :0
|
@@ -260,9 +308,16 @@ readme = ExampleDSLWriter.run do
|
|
260
308
|
'Fix: Moving files under files now moves up to parent folder of destination',
|
261
309
|
'Meta: Travis-CI integration',
|
262
310
|
],
|
311
|
+
'v0.0.3' => [
|
312
|
+
'New: Interactive mode with `-u`',
|
313
|
+
'New: Error and warning reporting with line numbers',
|
314
|
+
'New: Default configuration file at `~/.fled.yaml`',
|
315
|
+
'New: Editor and diff tool are configurable from configuration files',
|
316
|
+
'Meta: Refactoring of code',
|
317
|
+
],
|
263
318
|
}).sort { |a, b| b[0] <=> a[0] }.each do |version, changes|
|
264
319
|
em "Version #{version}"
|
265
|
-
|
320
|
+
li *changes
|
266
321
|
end
|
267
322
|
|
268
323
|
h2 "Disclaimer", <<-MD
|
@@ -276,4 +331,3 @@ readme = ExampleDSLWriter.run do
|
|
276
331
|
h2 "Licence", "[GPLv3](http://www.gnu.org/licenses/gpl-3.0.html)"
|
277
332
|
|
278
333
|
end
|
279
|
-
puts readme
|