raindown 0.14.0 → 0.15.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 +4 -4
- data/lib/raindown/cli.rb +2 -0
- data/lib/raindown/projects.rb +24 -4
- data/lib/raindown/rewriter.rb +1 -1
- data/lib/raindown/table/markdown_table.rb +9 -3
- data/lib/raindown/table/table.rb +74 -8
- data/lib/raindown/table/table_formulas.rb +50 -0
- data/lib/raindown/table/written_table.rb +68 -0
- data/lib/raindown/tui/navigator/commands.rb +7 -1
- data/lib/raindown/watcher/changes.rb +5 -3
- data/lib/raindown/watcher/supervisor.rb +1 -1
- data/lib/version.rb +1 -1
- metadata +6 -4
- /data/lib/raindown/{table_formatter.rb → table/table_formatter.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d201e22c68a6326752cd504b5cca6674384031244b3b91cbe9e8da2e1034d8b
|
|
4
|
+
data.tar.gz: 6b3cf1bbc8e03c353c0eb0bade6a7c1f9546c99fc2dfabc260963f50e7ff3063
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb8dba488c6c4ca2ddd49f8cd699a3d660f9a12fb00e756e6f5cd65e433b2ac04d4d4124e078a41b39fbe2707632f5cc1a78acf97e033dfdbe5715c01e50985b
|
|
7
|
+
data.tar.gz: 4d1d7f48804fcdc7ee6ce0343d2f34fa0f797566dc222a645dae1d3f4b79cc9f7841c6acbbfb83c93c0dde681bf110139f9ed51b4fd7ef7c37181db1052137fe
|
data/lib/raindown/cli.rb
CHANGED
|
@@ -76,6 +76,8 @@ module Raindown
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def self.run(argv)
|
|
79
|
+
# Markdown is UTF-8 whatever the locale, as an app opened from the Dock, like Obsidian, starts Raindown without one.
|
|
80
|
+
Encoding.default_external = Encoding::UTF_8
|
|
79
81
|
return if command(argv)
|
|
80
82
|
|
|
81
83
|
# Without a path, like "raindown", "raindown -x" or "raindown watch", it's the current directory.
|
data/lib/raindown/projects.rb
CHANGED
|
@@ -13,6 +13,7 @@ module Raindown
|
|
|
13
13
|
IGNORED = %w[node_modules vendor tmp pkg build dist coverage].freeze
|
|
14
14
|
# Ruby nodes and JavaScript Components.
|
|
15
15
|
NODE_EXTENSIONS = ['.rb', '.rbx', *JSNodes::EXTENSIONS].freeze
|
|
16
|
+
VAULT_FOLDER = '.obsidian'
|
|
16
17
|
|
|
17
18
|
module_function
|
|
18
19
|
|
|
@@ -23,11 +24,11 @@ module Raindown
|
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
# The folders below a directory with a .raindown folder. Only folders are walked, leaving out ignored, linked and
|
|
26
|
-
# gitignored ones, so it stays quick in a big folder like ~/dev.
|
|
27
|
+
# gitignored ones, so it stays quick in a big folder like ~/dev, and vaults, which their editor writes back to.
|
|
27
28
|
def project_folders(directory, gitignore = Gitignore.new(directory))
|
|
28
29
|
Dir.glob('*/', base: directory).flat_map do |folder|
|
|
29
30
|
path = File.join(directory, folder.chomp('/'))
|
|
30
|
-
next [] if ignored?(folder.chomp('/')) || File.symlink?(path) || gitignore.ignores?(path)
|
|
31
|
+
next [] if ignored?(folder.chomp('/')) || File.symlink?(path) || gitignore.ignores?(path) || vault?(path)
|
|
31
32
|
|
|
32
33
|
inside = project_folders(path, Gitignore.new(path, gitignore))
|
|
33
34
|
next inside unless project?(path)
|
|
@@ -44,13 +45,13 @@ module Raindown
|
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
# The project's Markdown files, sorted, leaving out ignored folders. The projects inside it are left out too,
|
|
47
|
-
# since they have nodes of their own.
|
|
48
|
+
# since they have nodes of their own, and vaults, which their editor writes back to.
|
|
48
49
|
def files(root)
|
|
49
50
|
files = []
|
|
50
51
|
|
|
51
52
|
Find.find(root) do |path|
|
|
52
53
|
if File.directory?(path)
|
|
53
|
-
Find.prune if path != root && (ignored?(File.basename(path)) || project?(path))
|
|
54
|
+
Find.prune if path != root && (ignored?(File.basename(path)) || project?(path) || vault?(path))
|
|
54
55
|
elsif markdown?(path, root:)
|
|
55
56
|
files << path
|
|
56
57
|
end
|
|
@@ -82,6 +83,25 @@ module Raindown
|
|
|
82
83
|
File.directory?(File.join(folder, Nodes::FOLDER))
|
|
83
84
|
end
|
|
84
85
|
|
|
86
|
+
# Whether a folder's an Obsidian vault, whose plugin runs a Raindown of its own, so one watching a folder above it
|
|
87
|
+
# leaves it alone, while one pointed at the vault itself doesn't.
|
|
88
|
+
def vault?(folder)
|
|
89
|
+
File.directory?(File.join(folder, VAULT_FOLDER))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Whether a path's in a vault below the directory, which isn't the directory itself.
|
|
93
|
+
def vault_below?(path, directory)
|
|
94
|
+
tops = [File.expand_path(directory), File.realpath(directory)]
|
|
95
|
+
folders = []
|
|
96
|
+
folder = File.dirname(File.expand_path(path))
|
|
97
|
+
until tops.include?(folder) || folder == File.dirname(folder)
|
|
98
|
+
folders << folder
|
|
99
|
+
folder = File.dirname(folder)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
tops.include?(folder) && folders.any? { vault?(it) }
|
|
103
|
+
end
|
|
104
|
+
|
|
85
105
|
def ignored?(folder)
|
|
86
106
|
folder.start_with?('.') || IGNORED.include?(folder)
|
|
87
107
|
end
|
data/lib/raindown/rewriter.rb
CHANGED
|
@@ -19,13 +19,19 @@ module Raindown
|
|
|
19
19
|
|
|
20
20
|
# The rows of the table in the lines, leaving out its separator, or none when they aren't a table.
|
|
21
21
|
def parse(lines)
|
|
22
|
+
padded_rows(lines).map { |row| row.map { cell(it) } }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The rows of the table in the lines, their cells as written, padding and all, leaving out its separator.
|
|
26
|
+
def padded_rows(lines)
|
|
22
27
|
return [] unless lines[1]&.strip&.match?(SEPARATOR)
|
|
23
28
|
|
|
24
|
-
[lines[0], *lines.drop(2)].take_while { it.strip.start_with?('|') }
|
|
29
|
+
table_lines = [lines[0], *lines.drop(2)].take_while { it.strip.start_with?('|') }
|
|
30
|
+
table_lines.map { it.strip.delete_prefix('|').delete_suffix('|').split(PIPE, -1) }
|
|
25
31
|
end
|
|
26
32
|
|
|
27
|
-
def
|
|
28
|
-
|
|
33
|
+
def cell(padded)
|
|
34
|
+
padded.strip.gsub('\|', '|')
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
def escape(cell)
|
data/lib/raindown/table/table.rb
CHANGED
|
@@ -6,6 +6,8 @@ require 'json'
|
|
|
6
6
|
|
|
7
7
|
require_relative '../node'
|
|
8
8
|
require_relative 'markdown_table'
|
|
9
|
+
require_relative 'table_formulas'
|
|
10
|
+
require_relative 'written_table'
|
|
9
11
|
|
|
10
12
|
module Raindown
|
|
11
13
|
# The node behind table:, a CSV or TSV file relative to the project as a Markdown table, after a comment of how many
|
|
@@ -17,13 +19,18 @@ module Raindown
|
|
|
17
19
|
# | Ada | engineer |
|
|
18
20
|
# | Lin | design |
|
|
19
21
|
# Edit the table and its rows are written back to the file, or edit the file and the table's written again. When
|
|
20
|
-
# both changed, neither is, and the table's comment says so until they match again.
|
|
22
|
+
# both changed, neither is, and the table's comment says so until they match again. With total: true, a bold row
|
|
23
|
+
# below the table sums its columns of numbers, which is worked out each time and never written to the file. Formula
|
|
24
|
+
# cells in the file, like =SUM(B), show their values, and keep their formulas while their values are left alone. Delete
|
|
25
|
+
# the padding around one's value and it shows its formula, to edit, until it's changed.
|
|
21
26
|
class Table < Node
|
|
22
27
|
COMMENT = /\A<!-- table (?:conflict|\d+ rows?) · (\h+) -->\z/
|
|
23
28
|
SEPARATORS = { '.csv' => ',', '.tsv' => "\t" }.freeze
|
|
29
|
+
BOLD = /\A\*\*.*\*\*\z/
|
|
24
30
|
|
|
25
|
-
def initialize(data)
|
|
31
|
+
def initialize(data, total: false)
|
|
26
32
|
@data = data
|
|
33
|
+
@total = total
|
|
27
34
|
end
|
|
28
35
|
|
|
29
36
|
# Written is what it wrote last time, so it can tell which of the table and the file changed since.
|
|
@@ -35,7 +42,7 @@ module Raindown
|
|
|
35
42
|
# Write-in, in <{ }>, the table only shows its file, and never writes to it.
|
|
36
43
|
def render(metadata: NoMetadata)
|
|
37
44
|
path = data_path(metadata)
|
|
38
|
-
Raindown.commonmark(data_error(path) || MarkdownTable.format(read_rows(path)))
|
|
45
|
+
Raindown.commonmark(data_error(path) || MarkdownTable.format(with_total(TableFormulas.evaluate(read_rows(path)))))
|
|
39
46
|
end
|
|
40
47
|
|
|
41
48
|
private
|
|
@@ -53,20 +60,79 @@ module Raindown
|
|
|
53
60
|
|
|
54
61
|
def synced(path, written)
|
|
55
62
|
file = read_rows(path)
|
|
63
|
+
shown = TableFormulas.evaluate(file)
|
|
56
64
|
synced_hash = written.first&.[](COMMENT, 1)
|
|
57
|
-
table =
|
|
58
|
-
return markdown(file) if
|
|
59
|
-
return markdown(write_rows(path, table)) if hash_rows(
|
|
65
|
+
table = WrittenTable.new(written_rows(written), file)
|
|
66
|
+
return markdown(file, table.revealed) if unchanged?(table.rows, synced_hash, shown)
|
|
67
|
+
return markdown(write_rows(path, with_formulas(table.rows, file, shown)), table.revealed) if hash_rows(shown) == synced_hash
|
|
60
68
|
|
|
61
69
|
warn "raindown: #{@data} and its table both changed, so neither is written until they match"
|
|
62
70
|
["<!-- table conflict · #{synced_hash} -->", *written.drop(1)].join("\n")
|
|
63
71
|
end
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
# Whether there's nothing to write back: the table's rows are as it wrote them, or as the file's are, or it's new.
|
|
74
|
+
def unchanged?(rows, synced_hash, shown)
|
|
75
|
+
synced_hash.nil? || rows.empty? || [synced_hash, hash_rows(shown)].include?(hash_rows(rows))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# The table's rows as it was written, padding and all, leaving out its total.
|
|
79
|
+
def written_rows(written)
|
|
80
|
+
header, *body = MarkdownTable.padded_rows(written.drop(1))
|
|
81
|
+
[header, *body.reject { total_row?(it.map(&:strip)) }].compact
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def markdown(rows, revealed = [])
|
|
66
85
|
return '' if rows.empty?
|
|
67
86
|
|
|
87
|
+
shown = TableFormulas.evaluate(rows)
|
|
68
88
|
count = rows.length - 1
|
|
69
|
-
|
|
89
|
+
table = MarkdownTable.format(with_total(with_revealed(shown, rows, revealed)))
|
|
90
|
+
"<!-- table #{count} row#{'s' unless count == 1} · #{hash_rows(shown)} -->\n#{table}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The values, but for each revealed cell, which shows its formula.
|
|
94
|
+
def with_revealed(values, rows, revealed)
|
|
95
|
+
revealed.each_with_object(values.map(&:dup)) { |(row, column), shown| shown[row][column] = rows[row][column] }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The table's rows, keeping the file's formula in each cell still showing its value.
|
|
99
|
+
def with_formulas(table, file, shown)
|
|
100
|
+
table.each_with_index.map do |row, row_index|
|
|
101
|
+
row.each_with_index.map do |cell, column|
|
|
102
|
+
formula = file.dig(row_index, column)
|
|
103
|
+
next formula if TableFormulas.formula?(formula) && shown.dig(row_index, column) == cell
|
|
104
|
+
|
|
105
|
+
cell
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def with_total(rows)
|
|
111
|
+
return rows unless @total && rows.length > 1
|
|
112
|
+
|
|
113
|
+
body = rows.drop(1)
|
|
114
|
+
sums = rows.first.each_index.map { |column| sum_cells(body.map { it[column].to_s }) }
|
|
115
|
+
sums[0] ||= 'Total'
|
|
116
|
+
[*rows, sums.map { bold_cell(it) }]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# The sum of cells that are all numbers, or blank, to the most decimal places any has, or nil when they aren't.
|
|
120
|
+
def sum_cells(cells)
|
|
121
|
+
numbers = cells.reject(&:empty?)
|
|
122
|
+
return if numbers.empty? || !numbers.all? { it.match?(TableFormulas::NUMBER) }
|
|
123
|
+
|
|
124
|
+
TableFormulas.sum(numbers)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def bold_cell(text)
|
|
128
|
+
return '' unless text
|
|
129
|
+
|
|
130
|
+
"**#{text}**"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# The total row it wrote, its cells bold or blank, which isn't one of the file's rows.
|
|
134
|
+
def total_row?(row)
|
|
135
|
+
row.any? { !it.empty? } && row.all? { it.empty? || it.match?(BOLD) }
|
|
70
136
|
end
|
|
71
137
|
|
|
72
138
|
def read_rows(path)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Raindown
|
|
4
|
+
# Formula cells in a table's rows, like =SUM(B), by its column's letter, or =sum(Price), by its header, worked out
|
|
5
|
+
# as spreadsheets do: the numbers in the column's other rows below the header, leaving out other formulas. Any other
|
|
6
|
+
# formula, or one naming no column, like one still being typed, is left as it's written.
|
|
7
|
+
module TableFormulas
|
|
8
|
+
NUMBER = /\A-?\d+(?:\.\d+)?\z/
|
|
9
|
+
SUM = /\A=SUM\(\s*([^)]+?)\s*\)\z/i
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def evaluate(rows)
|
|
14
|
+
header, *body = rows
|
|
15
|
+
return rows unless header
|
|
16
|
+
|
|
17
|
+
[header, *body.map { |row| row.map { sum_formula(it, header, body) || it } }]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def formula?(cell)
|
|
21
|
+
cell.to_s.match?(SUM)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The sum of the numbers, to the most decimal places any of them has.
|
|
25
|
+
def sum(numbers)
|
|
26
|
+
places = numbers.map { it[/\.(\d+)/, 1].to_s.length }.max.to_i
|
|
27
|
+
total = numbers.sum { Rational(it) }
|
|
28
|
+
return total.round.to_s if places.zero?
|
|
29
|
+
|
|
30
|
+
format("%.#{places}f", total)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def sum_formula(cell, header, body)
|
|
34
|
+
column_ref = cell[SUM, 1]
|
|
35
|
+
return unless column_ref
|
|
36
|
+
|
|
37
|
+
column = header.index { it.casecmp?(column_ref) } || column_index(column_ref)
|
|
38
|
+
return unless column && column < header.length
|
|
39
|
+
|
|
40
|
+
sum(body.map { it[column].to_s }.select { it.match?(NUMBER) })
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# A column's letters as its index, like B as 1 and AA as 26, or nil when they aren't letters.
|
|
44
|
+
def column_index(letters)
|
|
45
|
+
return unless letters.match?(/\A[A-Z]{1,3}\z/i)
|
|
46
|
+
|
|
47
|
+
letters.upcase.chars.reduce(0) { |index, letter| (index * 26) + letter.ord - 64 } - 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'unicode/display_width'
|
|
4
|
+
|
|
5
|
+
require_relative 'markdown_table'
|
|
6
|
+
require_relative 'table_formulas'
|
|
7
|
+
|
|
8
|
+
module Raindown
|
|
9
|
+
# A table: block's table as it was written, its cells padded as they were, against its file's rows. A formula cell
|
|
10
|
+
# shows its formula, so it can be edited, when its value's padding was deleted, no longer the width of its column's
|
|
11
|
+
# header, and keeps showing it, until it's changed from the file's, ignoring whitespace.
|
|
12
|
+
class WrittenTable
|
|
13
|
+
def initialize(padded_rows, file)
|
|
14
|
+
@padded_rows = padded_rows
|
|
15
|
+
@file = file
|
|
16
|
+
@values = TableFormulas.evaluate(file)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Its rows, as wide as each other, each formula still shown as it's saved being its value, as they're compared with the file's.
|
|
20
|
+
def rows
|
|
21
|
+
cells.each_with_index.map do |row, row_index|
|
|
22
|
+
row.each_with_index.map do |cell, column|
|
|
23
|
+
next @values.dig(row_index, column) if same_formula?(cell, @file.dig(row_index, column))
|
|
24
|
+
|
|
25
|
+
cell
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# The row and column of each cell to show as its formula.
|
|
31
|
+
def revealed
|
|
32
|
+
cells.each_with_index.flat_map do |row, row_index|
|
|
33
|
+
row.each_index.select { reveal?(row_index, it) }.map { [row_index, it] }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def cells
|
|
40
|
+
@cells ||= @padded_rows.map { |row| Array.new(width_in_cells) { MarkdownTable.cell(row[it].to_s) } }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# As wide as its widest row, as its file's rows are read, so a row still being typed reads the same in both.
|
|
44
|
+
def width_in_cells
|
|
45
|
+
@padded_rows.map(&:length).max
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reveal?(row, column)
|
|
49
|
+
formula = @file.dig(row, column)
|
|
50
|
+
return false unless TableFormulas.formula?(formula)
|
|
51
|
+
|
|
52
|
+
cell = cells[row][column]
|
|
53
|
+
same_formula?(cell, formula) || (cell == @values.dig(row, column) && squeezed?(row, column))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def same_formula?(cell, formula)
|
|
57
|
+
TableFormulas.formula?(formula) && cell.gsub(/\s+/, '') == formula.gsub(/\s+/, '')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def squeezed?(row, column)
|
|
61
|
+
width(@padded_rows[row][column]) != width(@padded_rows.first[column])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def width(padded)
|
|
65
|
+
Unicode::DisplayWidth.of(padded.to_s, emoji: :all)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -90,7 +90,7 @@ module Raindown
|
|
|
90
90
|
# and the files and endpoints are read again for the files added, removed or changed. When endpoints run as files
|
|
91
91
|
# are written back, like with -x, the screen says so while they do, as they can take a while.
|
|
92
92
|
def watched(paths)
|
|
93
|
-
changes = Watcher.changes(paths, root:)
|
|
93
|
+
changes = Watcher.changes(paths, directory: root, root: plain_root)
|
|
94
94
|
return reload if changes.any?(&:nodes?)
|
|
95
95
|
return if changes.empty?
|
|
96
96
|
|
|
@@ -100,6 +100,12 @@ module Raindown
|
|
|
100
100
|
Wait.new(message: "Writing back #{relative(saved.first)}...", task: -> { write_back_all(saved) })
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
# A file outside a project belongs to the folder only when it has no projects, as in a folder of notes. In one
|
|
104
|
+
# like ~/dev, only its projects are written back to, as they're all that's shown.
|
|
105
|
+
def plain_root
|
|
106
|
+
root if @workers.roots.empty?
|
|
107
|
+
end
|
|
108
|
+
|
|
103
109
|
def write_back_all(files)
|
|
104
110
|
files.each { write_back_saved(it) }
|
|
105
111
|
@files.load
|
|
@@ -19,10 +19,12 @@ module Raindown
|
|
|
19
19
|
Listen.to(directory, ignore: IGNORE) { |modified, added, removed| yield(modified + added + removed) }
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
# The changes among the paths, by the project each is in, the nearest one above it, or else the
|
|
23
|
-
# one, leaving out files that are neither nodes nor Markdown, or are in ignored folders.
|
|
24
|
-
def self.changes(paths, root: nil)
|
|
22
|
+
# The changes among the paths in the directory, by the project each is in, the nearest one above it, or else the
|
|
23
|
+
# root, when there is one, leaving out files that are neither nodes nor Markdown, or are in ignored folders or vaults.
|
|
24
|
+
def self.changes(paths, directory:, root: nil)
|
|
25
25
|
paths.filter_map do |path|
|
|
26
|
+
next if Projects.vault_below?(path, directory)
|
|
27
|
+
|
|
26
28
|
project = Projects.root(path) || root || next
|
|
27
29
|
next Change.new(root: project, path:, nodes: true) if Projects.node?(path, root: project)
|
|
28
30
|
|
|
@@ -42,7 +42,7 @@ module Raindown
|
|
|
42
42
|
# endpoint's request with -x, only holds up its own project. Without fork, the projects share this process, so
|
|
43
43
|
# they're taken in turn.
|
|
44
44
|
def handle(paths)
|
|
45
|
-
Watcher.changes(paths).each do |change|
|
|
45
|
+
Watcher.changes(paths, directory:).each do |change|
|
|
46
46
|
next unless change.nodes? || change.saved?
|
|
47
47
|
next take(change) unless fork?
|
|
48
48
|
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raindown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 1.
|
|
18
|
+
version: 1.5.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 1.
|
|
25
|
+
version: 1.5.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: commonmarker
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -254,7 +254,9 @@ files:
|
|
|
254
254
|
- lib/raindown/stat.rb
|
|
255
255
|
- lib/raindown/table/markdown_table.rb
|
|
256
256
|
- lib/raindown/table/table.rb
|
|
257
|
-
- lib/raindown/table_formatter.rb
|
|
257
|
+
- lib/raindown/table/table_formatter.rb
|
|
258
|
+
- lib/raindown/table/table_formulas.rb
|
|
259
|
+
- lib/raindown/table/written_table.rb
|
|
258
260
|
- lib/raindown/toc.rb
|
|
259
261
|
- lib/raindown/tui.rb
|
|
260
262
|
- lib/raindown/tui/blueprints/blueprints_renderer.rb
|
|
File without changes
|