summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrian m. carlson <sandals@crustytoothpaste.net>2020-10-24 22:24:50 +0000
committerbrian m. carlson <sandals@crustytoothpaste.net>2020-10-24 22:24:50 +0000
commit40a0c971ee228da6aff2fd384a666a16f271b06d (patch)
tree6aeaf7e359f522da2ca4245cda55ac9c8113a8d9
parent45d2ddc541dcbad5a17133a9b6c65a954de4820a (diff)
bin/format-text: handle lists and indentation gracefully
It can often be useful to include indented text, such as in a commit message, to indicate that some text is literal. We don't want to wrap such text. However, we also want to handle lists where we do want wrapping. Let's expand format-text to handle both these cases and format them nicely. Since this is tricky, let's add some specs for this case as well. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
-rwxr-xr-xbin/format-text39
-rw-r--r--spec/format_spec.rb124
-rw-r--r--spec/spec_helper.rb15
3 files changed, 176 insertions, 2 deletions
diff --git a/bin/format-text b/bin/format-text
index 3ff6251..4dfb1a9 100755
--- a/bin/format-text
+++ b/bin/format-text
@@ -3,7 +3,8 @@
#/ format-text [FILE...]
#/
#/ Formats text in the specified files or from stding, removing newlines within
-#/ a paragraph.
+#/ a paragraph. Indented blocks that are not part of a Markdown or AsciiDoc
+#/ numbered or bulleted list are preserved.
if ARGV[0] == "--help"
puts File.read($0).each_line.select { |l| l.start_with?("#/") }.
@@ -11,4 +12,38 @@ if ARGV[0] == "--help"
exit 0
end
-puts ARGF.read.split("\n\n").map { |c| c.gsub("\n", ' ') }.join("\n\n")
+puts (ARGF.set_encoding("UTF-8").read.split("\n\n").map do |c|
+ c.gsub(/\n\z/, '').split("\n").map do |l|
+ x = case l
+ when /^(\d+)?\. /
+ [:numbered, l]
+ when /^[-*•] /
+ [:bulleted, l]
+ when /^\s+/
+ [:indented, l]
+ else
+ [:normal, l]
+ end
+ x
+ end.inject([:start, []]) do |(now, accum), (state, l)|
+ new = if now == :start
+ state
+ elsif state == :indented
+ now
+ else
+ state
+ end
+ accum += if state == :indented && new != :indented
+ [l.gsub(/^\s+/, ' ')]
+ elsif now == :start
+ [l]
+ elsif new == :indented
+ ["\n", l]
+ elsif new == :normal
+ [' ', l]
+ else
+ ["\n", l]
+ end
+ [new, accum]
+ end[1].to_a.join
+end.to_a.join("\n\n"))
diff --git a/spec/format_spec.rb b/spec/format_spec.rb
new file mode 100644
index 0000000..a4808f3
--- /dev/null
+++ b/spec/format_spec.rb
@@ -0,0 +1,124 @@
+require_relative 'spec_helper'
+
+describe :format_text do
+ before(:all) do
+ @dir = TestDir.new
+ end
+
+ context 'editor' do
+ it 'should wrap lines' do
+ input = <<~EOF
+ This is some input.
+ This is some more input.
+ More text.
+
+ Text.
+ More text.
+ EOF
+ output = <<~EOF
+ This is some input. This is some more input. More text.
+
+ Text. More text.
+ EOF
+ expect(@dir.stream(['bin/format-text'], input)).to eq output
+ end
+
+ it 'should not wrap lines beginning with indentation' do
+ input = <<~EOF
+ This is some input.
+ This is some more input.
+ More text.
+
+ This is some indented text.
+ More indented text.
+
+ Text.
+ More text.
+ EOF
+ output = <<~EOF
+ This is some input. This is some more input. More text.
+
+ This is some indented text.
+ More indented text.
+
+ Text. More text.
+ EOF
+ expect(@dir.stream(['bin/format-text'], input)).to eq output
+ end
+
+ it 'should wrap indented lines in a bulleted list' do
+ input = <<~EOF
+ This is some input.
+ This is some more input.
+ More text.
+
+ - This is a list.
+ More stuff in the list.
+ - This is also a list.
+ More stuff.
+
+ Text.
+ More text.
+ EOF
+ output = <<~EOF
+ This is some input. This is some more input. More text.
+
+ - This is a list. More stuff in the list.
+ - This is also a list. More stuff.
+
+ Text. More text.
+ EOF
+ expect(@dir.stream(['bin/format-text'], input)).to eq output
+ expect(@dir.stream(['bin/format-text'], input.gsub('-', '*'))).to eq output.gsub('-', '*')
+ expect(@dir.stream(['bin/format-text'], input.gsub('-', '•'))).to eq output.gsub('-', '•')
+ end
+
+ it 'should wrap indented lines in a numbered list' do
+ input = <<~EOF
+ This is some input.
+ This is some more input.
+ More text.
+
+ 1. This is a list.
+ More stuff in the list.
+ 2. This is also a list.
+ More stuff.
+
+ Text.
+ More text.
+ EOF
+ output = <<~EOF
+ This is some input. This is some more input. More text.
+
+ 1. This is a list. More stuff in the list.
+ 2. This is also a list. More stuff.
+
+ Text. More text.
+ EOF
+ expect(@dir.stream(['bin/format-text'], input)).to eq output
+
+ input = <<~EOF
+ This is some input.
+ This is some more input.
+ More text.
+
+ . This is a list.
+ More stuff in the list.
+ . This is also a list.
+ More stuff.
+
+ Text.
+ More text.
+ EOF
+ output = <<~EOF
+ This is some input. This is some more input. More text.
+
+ . This is a list. More stuff in the list.
+ . This is also a list. More stuff.
+
+ Text. More text.
+ EOF
+ expect(@dir.stream(['bin/format-text'], input)).to eq output
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 472956b..df16c17 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,3 +1,4 @@
+require 'tempfile'
require 'tmpdir'
class TestDir
@@ -11,4 +12,18 @@ class TestDir
env["PATH"] = ENV["PATH"]
IO.popen(env, command, :unsetenv_others => true, :in => "/dev/null", :chdir => @dir).read
end
+
+ def stream(command, input, **env)
+ env["HOME"] = @dir
+ env["PATH"] = ENV["PATH"]
+ file = Tempfile.new()
+ begin
+ file.write(input)
+ file.flush
+ IO.popen(env, command, :unsetenv_others => true, :in => file.path, :err => "/dev/stderr", :chdir => @dir).read
+ ensure
+ file.close
+ file.unlink
+ end
+ end
end