leg 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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