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
@@ -0,0 +1,29 @@
1
+ module Leg
2
+ module Commands
3
+ class Diff < BaseCommand
4
+ def self.name
5
+ "diff"
6
+ end
7
+
8
+ def self.summary
9
+ "Compare last step with changes made in step/."
10
+ end
11
+
12
+ def self.usage
13
+ ""
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ @git.copy_step_to_repo!
23
+ FileUtils.cd(@git.repo_path) do
24
+ system("git diff")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ module Leg
2
+ module Commands
3
+ class Help < BaseCommand
4
+ def self.name
5
+ "help"
6
+ end
7
+
8
+ def self.summary
9
+ "Print out list of commands, or get help\n" +
10
+ "on a specific command."
11
+ end
12
+
13
+ def self.usage
14
+ "[<command>]"
15
+ end
16
+
17
+ def setopts!(o)
18
+ end
19
+
20
+ def run
21
+ if @args.empty?
22
+ puts "<< Hello! I am leg, version #{Leg::VERSION} >>"
23
+ puts
24
+ puts "Usage: leg <command> [args...]"
25
+ puts
26
+ puts "Commands:"
27
+ Leg::Commands::LIST.each do |cmd|
28
+ puts " #{cmd.name} #{cmd.usage}"
29
+ cmd.summary.split("\n").each do |line|
30
+ puts " #{line}"
31
+ end
32
+ end
33
+ puts
34
+ puts "For more help on a specific command, run `leg help <command>`."
35
+ elsif cmd = Leg::Commands::LIST.find { |cmd| cmd.name == @args.first }
36
+ cmd.new(["--help"], @config)
37
+ else
38
+ puts "There is no '#{@args.first}' command."
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,46 @@
1
+ module Leg
2
+ module Commands
3
+ class Init < BaseCommand
4
+ def self.name
5
+ "init"
6
+ end
7
+
8
+ def self.summary
9
+ "Initialize a new leg project."
10
+ end
11
+
12
+ def self.usage
13
+ "[new-dir]"
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ if @config
21
+ puts "You are already in a leg working directory."
22
+ return false
23
+ end
24
+
25
+ if new_dir = @args.first
26
+ if File.exist?(new_dir)
27
+ puts "Error: directory already exists."
28
+ return false
29
+ end
30
+ FileUtils.mkdir(new_dir)
31
+ FileUtils.cd(new_dir)
32
+ end
33
+
34
+ FileUtils.mkdir_p(".leg/repo")
35
+ FileUtils.mkdir_p("step")
36
+ FileUtils.mkdir_p("doc")
37
+ File.write("doc/tutorial.litdiff", "")
38
+ File.write("leg.yml", "---\n")
39
+
40
+ config = Leg::Config.new(FileUtils.pwd)
41
+ git = Leg::Representations::Git.new(config)
42
+ git.init!
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,26 @@
1
+ module Leg
2
+ module Commands
3
+ class Reset < BaseCommand
4
+ def self.name
5
+ "reset"
6
+ end
7
+
8
+ def self.summary
9
+ "Abort any saves in progress and checkout the top-most step."
10
+ end
11
+
12
+ def self.usage
13
+ ""
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ @git.reset!
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ module Leg
2
+ module Commands
3
+ class Resolve < BaseCommand
4
+ def self.name
5
+ "resolve"
6
+ end
7
+
8
+ def self.summary
9
+ "Continue rewriting steps after resolving a merge conflict."
10
+ end
11
+
12
+ def self.usage
13
+ ""
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ if @git.resolve!
23
+ git_to_litdiff!
24
+ output "Success!\n"
25
+ else
26
+ output "Looks like you've got a conflict to resolve!\n"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module Leg
2
+ module Commands
3
+ class Save < BaseCommand
4
+ def self.name
5
+ "save"
6
+ end
7
+
8
+ def self.summary
9
+ "Save changes to doc/."
10
+ end
11
+
12
+ def self.usage
13
+ ""
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ if @git.rebase_remaining!
23
+ git_to_litdiff!
24
+ output "Success!\n"
25
+ else
26
+ output "Looks like you've got a conflict to resolve!\n"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ module Leg
2
+ module Commands
3
+ class Status < BaseCommand
4
+ def self.name
5
+ "status"
6
+ end
7
+
8
+ def self.summary
9
+ "Show unsaved changes and the state of the step/ folder."
10
+ end
11
+
12
+ def self.usage
13
+ ""
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ state = @git.state
23
+ case state.operation
24
+ when nil
25
+ if state.step_number.nil?
26
+ output "Nothing to report.\n"
27
+ else
28
+ output "Step #{state.step_number} checked out into step/.\n"
29
+ end
30
+ when :commit
31
+ if state.args[1]
32
+ output "Amended step #{state.step_number}. "
33
+ end
34
+ if state.args[0] > 0
35
+ output "Added #{state.args[0]} step#{'s' if state.args[0] != 1} after step #{state.step_number}."
36
+ end
37
+ output "\n"
38
+ else
39
+ raise "unknown operation"
40
+ end
41
+
42
+ if state.conflict
43
+ output "\n"
44
+ output "Currently in a merge conflict. Resolve the conflict in step/ and\n"
45
+ output "run `leg resolve` to continue.\n"
46
+ elsif !state.operation.nil?
47
+ output "\n"
48
+ output "The above change(s) have not been saved yet. Run `leg save` to\n"
49
+ output "save to the doc/ folder.\n"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,31 @@
1
+ module Leg
2
+ module Commands
3
+ class Step < BaseCommand
4
+ def self.name
5
+ "step"
6
+ end
7
+
8
+ def self.summary
9
+ "Select a step for editing."
10
+ end
11
+
12
+ def self.usage
13
+ "<step-number>"
14
+ end
15
+
16
+ def setopts!(o)
17
+ end
18
+
19
+ def run
20
+ needs! :config, :repo
21
+
22
+ step_number = @args.first.to_i
23
+
24
+ unless @git.checkout!(@args.first.to_i)
25
+ output "Error: Step not found.\n"
26
+ return false
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ module Leg
2
+ class Config
3
+ attr_reader :path, :options
4
+
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def load!
10
+ @options = YAML.load_file(File.join(@path, "leg.yml"))
11
+ @options = {} unless @options.is_a? Hash
12
+ @options = symbolize_keys(@options)
13
+ end
14
+
15
+ def last_synced_at
16
+ File.mtime(last_synced_path) if File.exist?(last_synced_path)
17
+ end
18
+
19
+ def synced!
20
+ FileUtils.touch(last_synced_path)
21
+ end
22
+
23
+ private
24
+
25
+ def last_synced_path
26
+ File.join(@path, ".leg/last_synced")
27
+ end
28
+
29
+ def symbolize_keys(value)
30
+ case value
31
+ when Hash
32
+ value.map do |k, v|
33
+ [k.to_sym, symbolize_keys(v)]
34
+ end.to_h
35
+ when Array
36
+ value.map { |v| symbolize_keys(v) }
37
+ else
38
+ value
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,340 @@
1
+ module Leg
2
+ module DefaultTemplates
3
+ PAGE = {}
4
+ STEP = {}
5
+
6
+ PAGE["html"] = <<~TEMPLATE
7
+ <!doctype html>
8
+ <html>
9
+ <head>
10
+ <meta charset="utf-8">
11
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
12
+ <title><%= page_number %>. <%= page_title %></title>
13
+ <link href="style.css" rel="stylesheet">
14
+ </head>
15
+ <body>
16
+ <header class="bar">
17
+ <nav>
18
+ <% if prev_page %>
19
+ <a href="<%= prev_page.filename %>.html">&larr; prev</a>
20
+ <% else %>
21
+ <a href="#"></a>
22
+ <% end %>
23
+
24
+ <a href="<%= pages.first.filename %>.html">beginning</a>
25
+
26
+ <% if next_page %>
27
+ <a href="<%= next_page.filename %>.html">next &rarr;</a>
28
+ <% else %>
29
+ <a href="#"></a>
30
+ <% end %>
31
+ </nav>
32
+ </header>
33
+ <div id="container">
34
+ <%= content %>
35
+ </div>
36
+ </body>
37
+ </html>
38
+ TEMPLATE
39
+
40
+ STEP["html"] = <<~TEMPLATE
41
+ <div class="step">
42
+ <div class="step-number">
43
+ <%= number %>
44
+ </div>
45
+
46
+ <% for diff in diffs %>
47
+ <% diff = Leg::DiffTransformers::SyntaxHighlight.new.transform(diff) %>
48
+ <div class="diff">
49
+ <div class="diff-header">
50
+ <div class="diff-summary">
51
+ <%= markdown(summary) %>
52
+ </div>
53
+ <div class="diff-filename">
54
+ <%= diff.filename %>
55
+ </div>
56
+ </div>
57
+ <div class="diff-code">
58
+ <table>
59
+ <% for line in diff.lines %>
60
+ <tr>
61
+ <td class="line-number">
62
+ <%= line.line_number %>
63
+ </td>
64
+ <td class="line <%= diff.is_new_file ? :unchanged : line.type %>">\\
65
+ <% if line.type == :folded %>\\
66
+ <%= line.source.gsub('<span class="err">…</span>', '…') %>\\
67
+ <% else %>\\
68
+ <%= line.source %>\\
69
+ <% end %>\\
70
+ </td>
71
+ </tr>
72
+ <% end %>
73
+ </table>
74
+ </div>
75
+ </div>
76
+ <% end %>
77
+ </div>
78
+ TEMPLATE
79
+
80
+ PAGE["md"] = <<~TEMPLATE
81
+ <%= content %>
82
+ TEMPLATE
83
+
84
+ STEP["md"] = <<~TEMPLATE
85
+ ## <%= number %>. <%= summary %>
86
+
87
+ <% for diff in diffs %>\\
88
+ ```diff
89
+ // <%= diff.filename %>
90
+ <% for line in diff.lines %>\\
91
+ <%= { added: '+', removed: '-', unchanged: ' ', folded: '@' }[line.type] + line.source %>
92
+ <% end %>\\
93
+ ```
94
+ <% end %>
95
+ TEMPLATE
96
+
97
+ CSS = <<~TEMPLATE
98
+ * {
99
+ margin: 0;
100
+ padding: 0;
101
+ box-sizing: border-box;
102
+ }
103
+
104
+ body {
105
+ font-family: Utopia, Georgia, Times, 'Apple Symbols', serif;
106
+ line-height: 140%;
107
+ color: #333;
108
+ font-size: 18px;
109
+ }
110
+
111
+ #container {
112
+ width: 750px;
113
+ margin: 18px auto;
114
+ }
115
+
116
+ .bar {
117
+ display: block;
118
+ width: 100%;
119
+ background-color: #ceb;
120
+ box-shadow: 0px 0px 15px 1px #ddd;
121
+ }
122
+
123
+ .bar > nav {
124
+ display: flex;
125
+ justify-content: space-between;
126
+ width: 700px;
127
+ margin: 0 auto;
128
+ }
129
+
130
+ footer.bar > nav {
131
+ justify-content: center;
132
+ }
133
+
134
+ .bar > nav > a {
135
+ display: block;
136
+ padding: 2px 0 4px 0;
137
+ color: #152;
138
+ }
139
+
140
+ h1, h2, h3, h4, h5, h6 {
141
+ font-family: Futura, Helvetica, Arial, sans-serif;
142
+ color: #222;
143
+ line-height: 100%;
144
+ margin-top: 32px;
145
+ }
146
+
147
+ h2 a, h3 a, h4 a {
148
+ color: inherit;
149
+ text-decoration: none;
150
+ }
151
+
152
+ h2 a::before, h3 a::before, h4 a::before {
153
+ content: '#';
154
+ color: #fff;
155
+ font-weight: normal;
156
+ transition: color 0.15s ease;
157
+ display: block;
158
+ float: left;
159
+ width: 32px;
160
+ margin-left: -32px;
161
+ }
162
+
163
+ h2 a:hover::before, h3 a:hover::before, h4 a:hover::before {
164
+ color: #ccc;
165
+ }
166
+
167
+ h1 {
168
+ margin-top: 0;
169
+ font-size: 38px;
170
+ border-bottom: 3px solid #e7c;
171
+ display: inline-block;
172
+ }
173
+
174
+ h2 {
175
+ font-size: 26px;
176
+ }
177
+
178
+ p {
179
+ margin-top: 18px;
180
+ }
181
+
182
+ ul, ol {
183
+ margin-top: 18px;
184
+ margin-left: 36px;
185
+ }
186
+
187
+ hr {
188
+ border: none;
189
+ border-bottom: 1px solid #888;
190
+ }
191
+
192
+ a {
193
+ color: #26d;
194
+ }
195
+
196
+ code {
197
+ font-family: monospace;
198
+ font-size: inherit;
199
+ white-space: nowrap;
200
+ background-color: #eff4ea;
201
+ padding: 1px 3px;
202
+ }
203
+
204
+ h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
205
+ font-weight: normal;
206
+ }
207
+
208
+ kbd {
209
+ font-family: monospace;
210
+ border-radius: 3px;
211
+ padding: 2px 3px;
212
+ box-shadow: 1px 1px 1px #777;
213
+ margin: 2px;
214
+ font-size: 14px;
215
+ background: #f7f7f7;
216
+ font-weight: 500;
217
+ color: #555;
218
+ white-space: nowrap;
219
+ }
220
+
221
+ h1 kbd, h2 kbd, h3 kbd, h4 kbd, h5 kbd, h6 kbd {
222
+ font-size: 80%;
223
+ }
224
+
225
+ .step {
226
+ margin-top: 18px;
227
+ }
228
+
229
+ .step-number {
230
+ position: absolute;
231
+ margin-top: -6px;
232
+ margin-left: -148px;
233
+ font-size: 48px;
234
+ font-family: Helvetica, sans-serif;
235
+ line-height: 130%;
236
+ width: 128px;
237
+ text-align: right;
238
+ }
239
+
240
+ .diff {
241
+ border: 1px solid #ede7e3;
242
+ border-radius: 3px;
243
+ }
244
+
245
+ .diff .diff-header {
246
+ display: flex;
247
+ justify-content: space-between;
248
+ align-items: center;
249
+ padding: 7px 10px;
250
+ background-color: #fafbfc;
251
+ border-bottom: 1px solid #ede7e3;
252
+ font-size: 16px;
253
+ }
254
+
255
+ .diff .diff-summary {
256
+ color: #666;
257
+ font-size: 18px;
258
+ }
259
+
260
+ .diff .diff-summary p {
261
+ margin-top: 0;
262
+ }
263
+
264
+ .diff .diff-filename {
265
+ color: #666;
266
+ font-weight: bold;
267
+ }
268
+
269
+ .diff table {
270
+ width: 100%;
271
+ border-spacing: 0;
272
+ border-collapse: collapse;
273
+ }
274
+
275
+ .diff tr {
276
+ height: 20px;
277
+ line-height: 20px;
278
+ padding: 0 5px;
279
+ background-color: #fff;
280
+ font-family: monospace;
281
+ font-size: 14px;
282
+ }
283
+
284
+ .diff td.line-number {
285
+ width: 1%;
286
+ min-width: 55px;
287
+ text-align: right;
288
+ padding-right: 15px;
289
+ background-color: #fafbfc;
290
+ color: #ccc;
291
+ }
292
+
293
+ .diff td.line {
294
+ white-space: pre;
295
+ position: relative;
296
+ background-color: inherit;
297
+ padding-left: 5px;
298
+ }
299
+
300
+ .diff td.line.folded {
301
+ background-color: #eef;
302
+ opacity: 0.5;
303
+ }
304
+
305
+ .diff td.line.added {
306
+ background-color: #ffd;
307
+ text-decoration: none;
308
+ }
309
+
310
+ .diff td.line.removed {
311
+ background-color: #fdd;
312
+ text-decoration: line-through;
313
+ }
314
+
315
+ @media screen and (max-width: 700px) {
316
+ #container {
317
+ width: auto;
318
+ margin: 18px 0;
319
+ padding: 0 5px;
320
+ }
321
+
322
+ .bar > nav {
323
+ width: auto;
324
+ margin: 0;
325
+ padding: 0 5px;
326
+ }
327
+
328
+ .diff .diff-code {
329
+ overflow-x: scroll;
330
+ }
331
+
332
+ .diff .table {
333
+ width: 700px;
334
+ }
335
+ }
336
+
337
+ <%= syntax_highlighting_css ".line" %>
338
+ TEMPLATE
339
+ end
340
+ end