leg 0.0.1 → 0.0.2

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.
Files changed (78) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +10 -0
  3. data/CODE_OF_CONDUCT.md +74 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +34 -0
  6. data/LICENSE +21 -0
  7. data/README.md +59 -0
  8. data/Rakefile +11 -0
  9. data/TUTORIAL.md +243 -0
  10. data/bin/console +9 -0
  11. data/bin/setup +6 -0
  12. data/exe/leg +6 -0
  13. data/leg.gemspec +31 -0
  14. data/lib/leg.rb +27 -0
  15. data/lib/leg/cli.rb +42 -0
  16. data/lib/leg/commands.rb +19 -0
  17. data/lib/leg/commands/amend.rb +49 -0
  18. data/lib/leg/commands/base_command.rb +99 -0
  19. data/lib/leg/commands/build.rb +126 -0
  20. data/lib/leg/commands/commit.rb +48 -0
  21. data/lib/leg/commands/diff.rb +29 -0
  22. data/lib/leg/commands/help.rb +43 -0
  23. data/lib/leg/commands/init.rb +46 -0
  24. data/lib/leg/commands/reset.rb +26 -0
  25. data/lib/leg/commands/resolve.rb +31 -0
  26. data/lib/leg/commands/save.rb +31 -0
  27. data/lib/leg/commands/status.rb +54 -0
  28. data/lib/leg/commands/step.rb +31 -0
  29. data/lib/leg/config.rb +42 -0
  30. data/lib/leg/default_templates.rb +340 -0
  31. data/lib/leg/diff.rb +151 -0
  32. data/lib/leg/diff_transformers.rb +11 -0
  33. data/lib/leg/diff_transformers/base_transformer.rb +13 -0
  34. data/lib/leg/diff_transformers/fold_sections.rb +89 -0
  35. data/lib/leg/diff_transformers/omit_adjacent_removals.rb +38 -0
  36. data/lib/leg/diff_transformers/syntax_highlight.rb +32 -0
  37. data/lib/leg/diff_transformers/trim_blank_lines.rb +25 -0
  38. data/lib/leg/line.rb +83 -0
  39. data/lib/leg/markdown.rb +20 -0
  40. data/lib/leg/page.rb +27 -0
  41. data/lib/leg/representations.rb +9 -0
  42. data/lib/leg/representations/base_representation.rb +42 -0
  43. data/lib/leg/representations/git.rb +388 -0
  44. data/lib/leg/representations/litdiff.rb +85 -0
  45. data/lib/leg/step.rb +16 -0
  46. data/lib/leg/template.rb +95 -0
  47. data/lib/leg/tutorial.rb +49 -0
  48. data/lib/leg/version.rb +3 -0
  49. metadata +112 -38
  50. data/bin/leg +0 -9
  51. data/lib/snaptoken.rb +0 -24
  52. data/lib/snaptoken/cli.rb +0 -61
  53. data/lib/snaptoken/commands.rb +0 -13
  54. data/lib/snaptoken/commands/amend.rb +0 -27
  55. data/lib/snaptoken/commands/base_command.rb +0 -92
  56. data/lib/snaptoken/commands/build.rb +0 -107
  57. data/lib/snaptoken/commands/commit.rb +0 -27
  58. data/lib/snaptoken/commands/help.rb +0 -38
  59. data/lib/snaptoken/commands/resolve.rb +0 -27
  60. data/lib/snaptoken/commands/status.rb +0 -21
  61. data/lib/snaptoken/commands/step.rb +0 -35
  62. data/lib/snaptoken/default_templates.rb +0 -287
  63. data/lib/snaptoken/diff.rb +0 -180
  64. data/lib/snaptoken/diff_line.rb +0 -54
  65. data/lib/snaptoken/diff_transformers.rb +0 -9
  66. data/lib/snaptoken/diff_transformers/base_transformer.rb +0 -9
  67. data/lib/snaptoken/diff_transformers/fold_sections.rb +0 -85
  68. data/lib/snaptoken/diff_transformers/omit_adjacent_removals.rb +0 -28
  69. data/lib/snaptoken/diff_transformers/trim_blank_lines.rb +0 -21
  70. data/lib/snaptoken/markdown.rb +0 -18
  71. data/lib/snaptoken/page.rb +0 -64
  72. data/lib/snaptoken/representations.rb +0 -8
  73. data/lib/snaptoken/representations/base_representation.rb +0 -38
  74. data/lib/snaptoken/representations/git.rb +0 -262
  75. data/lib/snaptoken/representations/litdiff.rb +0 -81
  76. data/lib/snaptoken/step.rb +0 -27
  77. data/lib/snaptoken/template.rb +0 -53
  78. data/lib/snaptoken/tutorial.rb +0 -64
@@ -1,35 +0,0 @@
1
- class Snaptoken::Commands::Step < Snaptoken::Commands::BaseCommand
2
- def self.name
3
- "step"
4
- end
5
-
6
- def self.summary
7
- "Select a step for editing."
8
- end
9
-
10
- def self.usage
11
- "<step-number>"
12
- end
13
-
14
- def setopts!(o)
15
- end
16
-
17
- def run
18
- needs! :config, :repo
19
-
20
- step_number = @args.first.to_i
21
-
22
- FileUtils.cd(@git.repo_path) do
23
- @git.each_step do |cur_step, commit|
24
- if cur_step == step_number
25
- `git checkout #{commit.oid}`
26
- @git.copy_repo_to_step!
27
- exit
28
- end
29
- end
30
-
31
- puts "Error: Step not found."
32
- exit 1
33
- end
34
- end
35
- end
@@ -1,287 +0,0 @@
1
- module Snaptoken::DefaultTemplates
2
- PAGE = <<~TEMPLATE
3
- <!doctype html>
4
- <html>
5
- <head>
6
- <meta charset="utf-8">
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
8
- <title><%= page_number %>. <%= page_title %></title>
9
- <link href="style.css" rel="stylesheet">
10
- </head>
11
- <body>
12
- <header class="bar">
13
- <nav>
14
- <% if prev_page %>
15
- <a href="<%= prev_page.filename %>.html">&larr; prev</a>
16
- <% else %>
17
- <a href="#"></a>
18
- <% end %>
19
-
20
- <a href="<%= pages.first.filename %>.html">beginning</a>
21
-
22
- <% if next_page %>
23
- <a href="<%= next_page.filename %>.html">next &rarr;</a>
24
- <% else %>
25
- <a href="#"></a>
26
- <% end %>
27
- </nav>
28
- </header>
29
- <div id="container">
30
- <%= content %>
31
- </div>
32
- <footer class="bar">
33
- <nav>
34
- <a href="#">top of page</a>
35
- </nav>
36
- </footer>
37
- </body>
38
- </html>
39
- TEMPLATE
40
-
41
- STEP = <<~TEMPLATE
42
- <% for diff in diffs %>
43
- <div class="diff">
44
- <div class="diff-header">
45
- <div class="step-filename">
46
- <%= diff.filename %>
47
- </div>
48
- <div class="step-number">
49
- Step <%= number %>
50
- </div>
51
- </div>
52
- <pre class="highlight"><code>\\
53
- <% for line in diff.lines %>\\
54
- <% if line.type == :folded %>\\
55
- <div class="line folded">\\
56
- <%= line.source.gsub('<span class="err">…</span>', '…') %>\\
57
- </div>\\
58
- <% else %>\\
59
- <% tag = {unchanged: :div, added: :ins, removed: :del}[line.type] %>\\
60
- <% tag = :div if diff.is_new_file %>\\
61
- <<%= tag %> class="line">\\
62
- <%= line.source %>\\
63
- </<%= tag %>>\\
64
- <% end %>\\
65
- <% end %>\\
66
- </code></pre>
67
- </div>
68
- <% end %>
69
- TEMPLATE
70
-
71
- CSS = <<~TEMPLATE
72
- * {
73
- margin: 0;
74
- padding: 0;
75
- box-sizing: border-box;
76
- }
77
-
78
- body {
79
- font-family: Utopia, Georgia, Times, 'Apple Symbols', serif;
80
- line-height: 140%;
81
- color: #333;
82
- font-size: 18px;
83
- }
84
-
85
- #container {
86
- width: 700px;
87
- margin: 18px auto;
88
- }
89
-
90
- .bar {
91
- display: block;
92
- width: 100%;
93
- background-color: #ceb;
94
- box-shadow: 0px 0px 15px 1px #ddd;
95
- }
96
-
97
- .bar > nav {
98
- display: flex;
99
- justify-content: space-between;
100
- width: 700px;
101
- margin: 0 auto;
102
- }
103
-
104
- footer.bar > nav {
105
- justify-content: center;
106
- }
107
-
108
- .bar > nav > a {
109
- display: block;
110
- padding: 2px 0 4px 0;
111
- color: #152;
112
- }
113
-
114
- h1, h2, h3, h4, h5, h6 {
115
- font-family: Futura, Helvetica, Arial, sans-serif;
116
- color: #222;
117
- line-height: 100%;
118
- margin-top: 32px;
119
- }
120
-
121
- h2 a, h3 a, h4 a {
122
- color: inherit;
123
- text-decoration: none;
124
- }
125
-
126
- h2 a::before, h3 a::before, h4 a::before {
127
- content: '#';
128
- color: #fff;
129
- font-weight: normal;
130
- transition: color 0.15s ease;
131
- display: block;
132
- float: left;
133
- width: 32px;
134
- margin-left: -32px;
135
- }
136
-
137
- h2 a:hover::before, h3 a:hover::before, h4 a:hover::before {
138
- color: #ccc;
139
- }
140
-
141
- h1 {
142
- margin-top: 0;
143
- font-size: 38px;
144
- border-bottom: 3px solid #e7c;
145
- display: inline-block;
146
- }
147
-
148
- h2 {
149
- font-size: 26px;
150
- }
151
-
152
- p {
153
- margin-top: 18px;
154
- }
155
-
156
- ul, ol {
157
- margin-top: 18px;
158
- margin-left: 36px;
159
- }
160
-
161
- hr {
162
- border: none;
163
- border-bottom: 1px solid #888;
164
- }
165
-
166
- a {
167
- color: #26d;
168
- }
169
-
170
- code {
171
- font-family: monospace;
172
- font-size: inherit;
173
- white-space: nowrap;
174
- background-color: #eff4ea;
175
- padding: 1px 3px;
176
- }
177
-
178
- h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
179
- font-weight: normal;
180
- }
181
-
182
- kbd {
183
- font-family: monospace;
184
- border-radius: 3px;
185
- padding: 2px 3px;
186
- box-shadow: 1px 1px 1px #777;
187
- margin: 2px;
188
- font-size: 14px;
189
- background: #f7f7f7;
190
- font-weight: 500;
191
- color: #555;
192
- white-space: nowrap;
193
- }
194
-
195
- h1 kbd, h2 kbd, h3 kbd, h4 kbd, h5 kbd, h6 kbd {
196
- font-size: 80%;
197
- }
198
-
199
- .diff code {
200
- font-size: 14px;
201
- line-height: 20px;
202
- background-color: none;
203
- padding: 0;
204
- margin-bottom: 18px;
205
- white-space: inherit;
206
- }
207
-
208
- .diff pre {
209
- background-color: #fffcfa;
210
- padding: 5px 0;
211
- }
212
-
213
- .diff {
214
- border: 1px solid #ede7e3;
215
- border-radius: 3px;
216
- margin-top: 18px;
217
- }
218
-
219
- .diff .diff-header {
220
- display: flex;
221
- justify-content: space-between;
222
- padding: 0 5px;
223
- background-color: #ede7e3;
224
- font-size: 16px;
225
- color: #666;
226
- }
227
-
228
- .diff .step-number {
229
- font-weight: bold;
230
- }
231
-
232
- .diff .step-filename {
233
- font-weight: bold;
234
- }
235
-
236
- .diff .step-name {
237
- font-family: monospace;
238
- font-size: 12px;
239
- }
240
-
241
- .diff .line {
242
- display: block;
243
- height: 20px;
244
- padding: 0 5px;
245
- position: relative;
246
- }
247
-
248
- .diff .line.folded {
249
- background-color: #eef;
250
- opacity: 0.5;
251
- }
252
-
253
- .diff ins.line {
254
- background-color: #ffd;
255
- text-decoration: none;
256
- }
257
-
258
- .diff del.line {
259
- background-color: #fdd;
260
- text-decoration: line-through;
261
- }
262
-
263
- @media screen and (max-width: 700px) {
264
- #container {
265
- width: auto;
266
- margin: 18px 0;
267
- padding: 0 5px;
268
- }
269
-
270
- .bar > nav {
271
- width: auto;
272
- margin: 0;
273
- padding: 0 5px;
274
- }
275
-
276
- .highlight {
277
- overflow-x: scroll;
278
- }
279
-
280
- .diff .line {
281
- width: 700px;
282
- }
283
- }
284
-
285
- <%= syntax_highlighting_css ".highlight" %>
286
- TEMPLATE
287
- end
@@ -1,180 +0,0 @@
1
- class Snaptoken::Diff
2
- attr_accessor :filename, :is_new_file, :lines, :syntax_highlighted
3
-
4
- def initialize(filename = nil, is_new_file = false, lines = [])
5
- @filename = filename
6
- @is_new_file = is_new_file
7
- @lines = lines
8
- @syntax_highlighted = false
9
- end
10
-
11
- def clone
12
- diff = Snaptoken::Diff.new(@filename.dup, @is_new_file, @lines.map(&:clone))
13
- diff.syntax_highlighted = @syntax_highlighted
14
- diff
15
- end
16
-
17
- def clone_empty
18
- diff = Snaptoken::Diff.new(@filename.dup, @is_new_file, [])
19
- diff.syntax_highlighted = @syntax_highlighted
20
- diff
21
- end
22
-
23
- # Append a DiffLine to the Diff.
24
- def <<(diff_line)
25
- unless diff_line.is_a? Snaptoken::DiffLine
26
- raise ArgumentError, "expected a DiffLine"
27
- end
28
- @lines << diff_line
29
- self
30
- end
31
-
32
- def to_patch(options = {})
33
- patch = "diff --git a/#{@filename} b/#{@filename}\n"
34
- if @is_new_file
35
- patch += "new file mode 100644\n"
36
- patch += "--- /dev/null\n"
37
- else
38
- patch += "--- a/#{@filename}\n"
39
- end
40
- patch += "+++ b/#{@filename}\n"
41
-
42
- find_hunks.each do |hunk|
43
- patch += hunk_header(hunk)
44
- hunk.each do |line|
45
- patch += line.to_patch(options)
46
- end
47
- end
48
-
49
- patch
50
- end
51
-
52
- # Parse a git diff and return an array of Diff objects, one for each file in
53
- # the git diff.
54
- def self.parse(git_diff)
55
- in_diff = false
56
- old_line_num = nil
57
- new_line_num = nil
58
- cur_diff = nil
59
- diffs = []
60
-
61
- git_diff.lines.each do |line|
62
- if line =~ /^diff --git (\S+) (\S+)$/
63
- filename = $2.split("/")[1..-1].join("/")
64
- cur_diff = Snaptoken::Diff.new(filename)
65
- diffs << cur_diff
66
- in_diff = false
67
- elsif !in_diff && line.start_with?('new file')
68
- cur_diff.is_new_file = true
69
- elsif line =~ /^@@ -(\d+)(,\d+)? \+(\d+)(,\d+)? @@/
70
- # TODO: somehow preserve function name that comes to the right of the @@ header?
71
- in_diff = true
72
- old_line_num = $1.to_i
73
- new_line_num = $3.to_i
74
- elsif in_diff && line[0] == '\\'
75
- # Ignore "".
76
- elsif in_diff && [' ', '|', '+', '-'].include?(line[0])
77
- case line[0]
78
- when ' ', '|'
79
- type = :unchanged
80
- line_nums = [old_line_num, new_line_num]
81
- old_line_num += 1
82
- new_line_num += 1
83
- when '+'
84
- type = :added
85
- line_nums = [nil, new_line_num]
86
- new_line_num += 1
87
- when '-'
88
- type = :removed
89
- line_nums = [old_line_num, nil]
90
- old_line_num += 1
91
- end
92
-
93
- cur_diff << Snaptoken::DiffLine.new(type, line[1..-1], line_nums)
94
- else
95
- in_diff = false
96
- end
97
- end
98
-
99
- diffs
100
- end
101
-
102
- class HTMLLineByLine < Rouge::Formatter
103
- def initialize(formatter)
104
- @formatter = formatter
105
- end
106
-
107
- def stream(tokens, &b)
108
- token_lines(tokens) do |line|
109
- line.each do |tok, val|
110
- yield @formatter.span(tok, val)
111
- end
112
- yield "\n"
113
- end
114
- end
115
- end
116
-
117
- SYNTAX_HIGHLIGHTER = HTMLLineByLine.new(Rouge::Formatters::HTML.new)
118
-
119
- def syntax_highlight!
120
- return if @syntax_highlighted
121
- code = @lines.map(&:source).join("\n") + "\n"
122
- lexer = Rouge::Lexer.guess(filename: @filename, source: code)
123
- SYNTAX_HIGHLIGHTER.format(lexer.lex(code)).lines.each.with_index do |line_hl, idx|
124
- @lines[idx].source = line_hl
125
- end
126
- @syntax_highlighted = true
127
- end
128
-
129
- private
130
-
131
- # :S
132
- def hunk_header(hunk)
133
- old_line, new_line = hunk.first.line_numbers
134
- old_line ||= 1
135
- new_line ||= 1
136
-
137
- old_count = hunk.count { |line| [:removed, :unchanged].include? line.type }
138
- new_count = hunk.count { |line| [:added, :unchanged].include? line.type }
139
-
140
- old_line = 0 if old_count == 0
141
- new_line = 0 if new_count == 0
142
-
143
- "@@ -#{old_line},#{old_count} +#{new_line},#{new_count} @@\n"
144
- end
145
-
146
- # :(
147
- def find_hunks
148
- raise "can't create patch from empty diff" if @lines.empty?
149
- hunks = []
150
- cur_hunk = [@lines.first]
151
- cur_line_nums = @lines.first.line_numbers.dup
152
- @lines[1..-1].each do |line|
153
- case line.type
154
- when :unchanged
155
- cur_line_nums[0] = cur_line_nums[0].nil? ? line.line_numbers[0] : (cur_line_nums[0] + 1)
156
- cur_line_nums[1] = cur_line_nums[1].nil? ? line.line_numbers[1] : (cur_line_nums[1] + 1)
157
- when :added
158
- cur_line_nums[1] = cur_line_nums[1].nil? ? line.line_numbers[1] : (cur_line_nums[1] + 1)
159
- when :removed
160
- cur_line_nums[0] = cur_line_nums[0].nil? ? line.line_numbers[0] : (cur_line_nums[0] + 1)
161
- when :folded
162
- raise "can't create patch from diff with folded lines"
163
- end
164
-
165
- old_match = (line.line_numbers[0].nil? || line.line_numbers[0] == cur_line_nums[0])
166
- new_match = (line.line_numbers[1].nil? || line.line_numbers[1] == cur_line_nums[1])
167
-
168
- if !old_match || !new_match
169
- hunks << cur_hunk
170
-
171
- cur_hunk = []
172
- cur_line_nums = line.line_numbers.dup
173
- end
174
-
175
- cur_hunk << line
176
- end
177
- hunks << cur_hunk
178
- hunks
179
- end
180
- end