/
index.html.dyck
721 lines (579 loc) · 26.5 KB
/
index.html.dyck
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Comby〔 Rewrite Code 〕</title>
<!-- Custom fonts for this theme -->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css">
<!-- Theme CSS -->
<link href="css/freelancer.min.css" rel="stylesheet">
<!-- Source Sans Pro font -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css">
<link rel="icon" href="img/favicon.ico" type="image/x-icon/">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-142487942-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-142487942-1');
</script>
</head>
<body id="page-top">
<!-- Masthead -->
<header class="masthead bg-primary text-center">
<div class="container masthead-container d-flex align-items-center flex-column">
<!-- Masthead Avatar Image -->
<!--<img class="masthead-avatar mb-5" src="img/avataaars.svg" alt="">-->
<!-- Masthead Heading -->
<h1 class="masthead-heading text-uppercase mb-0">Comby</h1>
<!-- Line -->
<div class="divider-line"></div>
<!-- Masthead Subheading -->
<p class="masthead-subheading font-weight-light mb-0"><code><span class="hole">change the way you change :[code]</span></code></p>
</div>
<!-- Panel -->
<div class="container media-width-override mt-5 pl-5 pr-5">
<div class="row">
<!-- Basic Usage -->
<div class="col-sm-2 offset-sm-1 panel-item">
<a href="#basic-usage">
<div class="mastpanel-item">
<div class="mastpanel-item-overlay h-100 w-100">
<img class="img-fluid" src="img/panel/hexa-cell-1-orange.svg" alt="">
<p>Basic Usage</p>
</div>
<img class="img-fluid" src="img/panel/hexa-cell-1.svg" alt="">
<p>Basic Usage</p>
</div>
</a>
</div>
<!-- Advanced Usage -->
<div class="col-sm-2 panel-item">
<a href="#advanced-usage">
<div class="mastpanel-item">
<div class="mastpanel-item-overlay h-100 w-100">
<img class="img-fluid" src="img/panel/hexa-cell-2-orange.svg" alt="">
<p>Advanced Usage</p>
</div>
<img class="img-fluid" src="img/panel/hexa-cell-2.svg" alt="">
<p>Advanced Usage</p>
</div>
</a>
</div>
<!-- Catalog -->
<div class="col-sm-2 panel-item">
<a href="https://catalog.comby.dev/">
<div class="mastpanel-item">
<div class="mastpanel-item-overlay h-100 w-100">
<img class="img-fluid" src="img/panel/reading-book-orange.svg" alt="">
<p>Catalog</p>
</div>
<img class="img-fluid" src="img/panel/reading-book.svg" alt="">
<p>Catalog</p>
</div>
</a>
</div>
<!-- Live -->
<div class="col-sm-2 panel-item">
<a href="https://comby.live/">
<div class="mastpanel-item">
<div class="mastpanel-item-overlay h-100 w-100 fucksakes">
<img class="img-fluid" src="img/panel/code-inspector-ui-orange.svg" alt="">
<p>Live</p>
</div>
<img class="img-fluid" src="img/panel/code-inspector-ui.svg" alt="">
<p>Live</p>
</div>
</a>
</div>
<!-- GitHub -->
<div class="col-sm-2 panel-item">
<a href="https://github.com/comby-tools/comby/">
<div class="mastpanel-item mx-auto">
<div class="mastpanel-item-overlay h-100 w-100">
<img class="img-fluid" src="img/panel/github-orange.svg" alt="">
<p>GitHub</p>
</div>
<img class="img-fluid" src="img/panel/github.svg" alt="">
<p>GitHub</p>
</div>
</a>
</div>
</div>
</div>
</header>
<!-- Philosophy Section -->
<section class="page-section bg-secondary portfolio" id="philosophy">
<div class="container">
<!--<h2 class="page-section-heading text-center">Philosophy</h2>-->
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
\p{Code is so interesting because simple linear sequences of characters
express rich non-linear structures (like trees) and arbitrary information
(like comments). Humans are very creative, and have developed a variety of
ways to order these characters to mean different things. For example,
C-like comments can start with \source{//} but Python-like comments use
\source{#}. Problematically, we use the same characters to mean different
things across languages and in different contexts: a \source{#} in C could
be the start of a macro. Or it could be part of a string like
\source{"#"}. Or it could be a meaningless character inside a C comment
like \source{// #}. Yet at some level, a choice of characters in all
languages correspond to similar underlying structures or information: most
languages have comments and balanced delimiters like parentheses
\source{()} or braces \source{{}} nest expressions, as found in typical
if-statements. The key idea in Comby is to match code that respects the
basics of this richer structure on a per-language basis, and not (only) as
arbitrary sequences of characters. Matching sequences of characters is
something that regex is really good for, but regex is not generally
powerful enough to recognize nested code structures. Regex also supports a
lot of additional functionality that can lead to complex patterns. Comby
tries to cut down on this complexity to make changing code easy, so you'll
find that regex-style match operators are absent in Comby. And that's
OK.}
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
</div>
</section>
<!-- Basic Usage Section -->
<section class="page-section bg-primary portfolio" id="basic-usage">
<div class="container">
<!-- Section Heading -->
<h2 class="page-section-heading text-center">Basic Usage</h2>
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
\p{Comby is a tool for matching and rewriting code. You start by writing a simple template to match syntax. Look at this Go function:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source func main() {
fmt.Println("hello world")
}
```
</div>
</div>
\p{We can match the arguments to \source{fmt.Println} with this <i>match template</i>:}
<div class="row">
<div class="col-sm-6 offset-sm-3">
```match
fmt.Println(:[arguments])
```
</div>
</div>
\p{The :[arguments] part is called a hole. It saves the matched part to a variable. In this case, the variable is called <code>arguments</code>, but we could have called it something else, like :[1] or :[the_1st_arg]. Your choice! As long as it only contains alphabet characters, numbers, or underscores.}
\p{The :[arguments] hole matches the \source{"hello world"} string. We can use it in a <i>rewrite template</i> to rewrite the function, like this one:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```rewrite
fmt.Println(fmt.Sprintf("comby says %s", :[arguments]))
```
</div>
</div>
\p{Comby takes the match and rewrite templates and replaces the matched part in place:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```source
func main() {
\rewrite{fmt.Println(fmt.Sprintf("comby says %s", "hello world"))}
}
```
[Live example](https://bit.ly/2XpttJG)
</div>
</div>
\p{Holes are the only special part in match templates, and they always have the form \color{:[...]}[orange]. <u>All other characters are interpreted literally</u> (there's a bit of detail about whitespace that we'll talk about in the next part). The point is that you <u>never</u> have to escape any characters in your template. Just say what you mean!}
\h6{How Matching Works}[#how-matching-works]
\p{:[hole] matches all characters, including newlines. If the match template was <i>just</i><br> :[file_content], it would match all the file content. The way :[hole] starts and stops matching depends on the code structure around it. Let's look at an example, matching on this Javascript code using the match template on the right:}
<div class="row">
<div class="col-sm-5 offset-sm-2">
```source
if (width <= 1280 && height <= 800) {
return 1;
}
```
[Live example](https://bit.ly/2Xiw1cf)
</div>
<div class="col-sm-3">
```match
if (:[var] <= :[rest])
```
</div>
</div>
\p{:[var] matches until it sees the \source{ <= } part coming after it and matches \match{width}. :[rest] matches the rest of the condition: \match{1280 && height <= 800}. These holes match lazily: they look for the shortest way to satisfy the match. One way to refine matching is to add concrete context around holes based on what we care about. For example, we could match \match{height} to :[height] with both of the following templates, which depends on matching different parts of surrounding code:}
<div class="row">
<div class="col-sm-4 offset-sm-2">
```match
if (:[_] && :[height] :[_])
```
</div>
<div class="col-sm-4">
```match
if (:[_] :[height] <= 800)
```
</div>
</div>
\h6{About whitespace}[about-whitespace]
\p{Comby tries to make matching code forgiving. Whitespace in the template, like a single space, multiple contiguous spaces, or newlines are interpreted all the same: Comby will match the corresponding whitespace in the source code, but will not care about matching the exact number of spaces, or distinguish between spaces and newlines. Not being strict about whitespace tends to be the right default decision for code in most languages. It means our previous match templates all still work in these cases where our Javascript code is formatted differently:}
<div class="row">
<div class="col-sm-4 offset-sm-2">
```source
if (width <= 1280
&& height <= 800) {
return 1;
}
```
[Live example](https://bit.ly/2Xh2tMk)
</div>
<div class="col-sm-4">
```source
if (width <= 1280
&& height <= 800) {
return 1;
}
```
[Live example](https://bit.ly/2XaGTZV)
</div>
</div>
\p{If you're wondering about indentation-sensitive languages like Python, be sure to check out the [FAQ]{#faq-what-about-python}.}
\h6{What makes Comby special: More about structural matching}[what-makes-comby-special]
\p{If holes only matched lazily and indiscriminately up to patterns
like \source{<=} it wouldn't be much more special than matching a sequence
of characters. But matching is smarter than that. In many languages,
balanced delimiters like \source{()}, \source{[]} and \source{{}}
are <u>always</u> balanced. By default, a match template like
\match{(:[1])} will only match characters <u>inside well-balanced
parentheses</u>. Here are two example matches in this code:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
result = foo\match{(\color{bar(x)}[orange])} + foobar\match{(\color{baz(x)}[orange])};
```
[Live example](https://bit.ly/2Xm12Mk)
</div>
</div>
\p{The hole binds to \source{bar(x)} and \source{baz(x)} respectively,
which we can easily rewrite to a different call \source{qux(x)}, for
example. The observant reader will notice that
\source{(\color{x}[orange])} are nested matches. By default, Comby will
match at the toplevel, but nested matches can be found with added
context (e.g., \match{bar(:[1])}), or by extracting and rerunning on
Comby on modified code. Note that writing a regular expression to do the
same is not easy (simple attempts like \source{\(.*\)}
<sup>[[]](https://regexr.com/4fssh)</sup> or \source{\(.*?\)}
<sup>[[]](https://regexr.com/4fssk)</sup> don't work).}
\p{Let's change the code above and make it a little more interesting.
Suppose it was this Javascript:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
var result = foo(bar(x \color{/* arg 1\unbalanced_right_paren */}[#57beef])) + foobar(\color{"\unbalanced_left_paren"}[yellow]);
```
</div>
</div>
\p{Now there's quite a bit of complexity if we want to match the
arguments of \source{foo} and \source{foobar}. A block comment
\source{\color{/* arg 1\unbalanced_right_paren */}[#57beef]} is inlined
for \source{foo}. Because this is a comment, it shouldn't matter whether
the parenthesis inside are balanced or not. The same goes for the string
literal argument to \source{foobar}: it's not a parenthesis in the code.
The special thing here is that our original match template
\match{(:[1])} can stay <u>exactly the same</u> and still matches the
two arguments (in this case, it captures the comment and string)}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
var result = foo\match{(\color{bar(x /* arg 1\unbalanced_right_paren */)}[orange])} + foobar(\match{\color{"\unbalanced_left_paren"}[orange]});
```
[Live example](https://bit.ly/2Zy5PYG)
</div>
</div>
\p{Comby understands this interaction between delimiters, strings, and
comments and makes reasonable guesses for your language based on file
extension (you can also force a particular matcher with a command line
option). And, you can always fall back to a generic matcher for files or
languages that are not explicitly supported.}
\p{Note that if we tried to use a regex above, our pattern would need to
understand that \source{/* */} delineates comments, otherwise it would
get confused by the parenthesis inside! The same problem comes up for
the string literal argument, which contains an unbalanced parenthesis. A
regular expression that takes all of this into account would get ugly
fast, and that's only for Javascript!}
\h6{A few more tips and tricks}[tips-and-tricks]
\p{\color{<i class="fas fa-lightbulb"></i>}[orange]
Using :[hole] inside string quotes will match only within the string
(for most languages). Comby also understands the difference between
escapable string literals (like \source{"}string\source{"} in C) and raw
string literals like \source{`}string\source{`} in Go, and will know to
stop between these delimiters. <sup>[[]](https://bit.ly/2WRnxEL)</sup>}
\p{\color{<i class="fas fa-lightbulb"></i>}[orange]
Use \color{:[[hole]]}[orange] to match only alphanumeric and
underscore characters. This hole does not match across newlines or
punctuation.<sup>[[]](https://bit.ly/2WUhPCa)</sup>}
\p{\color{<i class="fas fa-lightbulb"></i>}[orange]
You can refer to the same variable using either
\color{:[[hole]]}[orange] or :[hole] in the rewrite template.
<sup>[[]](https://bit.ly/2ZAQZR0)</sup>}
\p{\color{<i class="fas fa-lightbulb"></i>}[orange]
You almost never want to start a template with :[hole], since it
matches everything including newlines up to its suffix. This can make
things slow. :[hole] is typically useful inside balanced delimiters.<sup>[[]](https://bit.ly/2WVDzh7)</sup>}
\p{\color{<i class="fas fa-lightbulb"></i>}[orange]
Want more inspiration? Check out these simple code rewrites.<sup>[[]](https://catalog.comby.dev/)}
</div>
</div>
</section>
<!-- Advanced Usage Section -->
<section class="page-section bg-secondary portfolio" id="advanced-usage">
<div class="container">
<!-- Section Heading -->
<h2 class="page-section-heading text-center">Advanced Usage</h2>
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
\p{You can refine matches and rewrite templates with <i>rules</i> in Comby. Rules start with the word \source{where}. A rule can check whether two variables are syntactically equal. For example, we can check for duplicate expressions in if-conditions with the following match template and rule:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```match
if (:[left_side] && :[right_side])
```
</div>
</div>
<div class="row">
<div class="col-sm-4 offset-sm-2">
```source
where :[left_side] == :[right_side]
```
</div>
</div>
\p{This matches code where the programmer perhaps made a mistake and duplicated an expression without changing a variable like \source{x} to \source{y}:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
if (\match{x == 500} && \match{x == 500})
```
[Live example](https://bit.ly/2Na9UAS)
</div>
</div>
\p{You can use the \source{!=} operator to check inequality. Multiple conditions can be separated by a comma, and mean "logical and". The following adds a condition to ignore our match case above:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```source
where :[left_side] == :[right_side], :[left_side] != \color{"x == 500"}[yellow]
```
[Live example](https://bit.ly/2NaaCOy)
</div>
</div>
\p{Variables can be compared to other variables or string contents (enclosed by double quotes).}
\h6{Experimental language features}[experimental-language-features]
\p{Comby includes experimental language features for sub-matching on variables. These features are subject to change, but available if you want to experiment with it. Here is an example using the sub-matching syntax:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```source
where match :[left_side] {
| \color{"x == 600"}[yellow] -> false
| \color{"x == 500"}[yellow] -> true
}
```
[Live example](https://bit.ly/2NaGjaK)
</div>
</div>
\p{The \source{match { ... }} says to match the text bound to :[left_side] against each of the match cases \source{| match_case}, and to perform the filter on the right-hand side of the \source{->} when the pattern matches. Sub-matching statements can nest:}
<div class="row">
<div class="col-sm-8 offset-sm-2">
```source
where match :[left_side] {
| \color{"x == 500"}[yellow] ->
match :[right_side] {
| \color{"x == 500"}[yellow] -> true
| \color{"x == 600"}[yellow] -> false
}
| \color{"x == 600"}[yellow] -> false
}
```
</div>
</div>
</section>
<!-- Advanced Usage Section -->
<section class="page-section bg-primary portfolio" id="quick-reference">
<div class="container">
<!-- Section Heading -->
<h2 class="page-section-heading text-center">Quick Reference</h2>
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
\p{All the examples on [comby.live]{https://comby.live} and in the [catalog]{https://catalog.comby.dev} are just a copy away
from working on your command-line (just click on terminal). Install:}
<div class="offset-sm-3">\p{\rewrite{bash <(curl -sL get.comby.dev)}}</div>
\p{Here are some basics:}
\h6{Highlighted diff output for all go files in this directory and below}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
comby 'match :[template]' 'rewrite :[template]' .go
```
</div>
</div>
\h6{Replace in place for all go files in this directory and below}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
comby 'match :[template]' 'rewrite :[template]' .go -i
```
</div>
</div>
\h6{Diff output for all files starting with file.go in directory foo}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
comby 'match :[template]' 'rewrite :[template]' file.go -d foo
```
</div>
</div>
\h6{Force using the Javascript matcher for all .txt files}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
comby 'match :[template]' 'rewrite :[template]' .txt -matcher .js
```
</div>
</div>
\h6{Replace stdin using the generic matcher}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
echo "foo(a, b)" | comby 'foo(:[1], :[2])' 'bar(:[2], :[1])' -stdin
```
</div>
</div>
\p{Output:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```diff
\color{------ /dev/null}[red]
\color{++++++ /dev/null}[green]
\color{@|}[gray]-1,1 +1,1 ============================================================
\bgcolor{-|}[red]\color{foo}[red](\color{a}[red], \color{b}[red])
\bgcolor{+|}[green]\color{bar}[green](\color{b}[green], \color{a}[green])
```
</div>
</div>
\h6{As above, but a plain patch}[ref-1]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
echo "foo(a, b)" | comby 'foo(:[1], :[2])' 'bar(:[2], :[1])' -stdin -diff
```
</div>
</div>
\p{Output:}
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```diff
--- /dev/null
+++ /dev/null
@@ -1,1 +1,1 @@
-foo(a, b)
+bar(b, a)
```
</div>
</div>
\h6{Use a directory of template patterns instead of the command line}[ref-x]
<div class="row">
<div class="col-sm-8 offset-sm-2 mb-3">
```source
comby .go -templates /path/to/directory
```
</div>
</div>
\p{A rewrite pattern should be described by two files in
\source{path/to/directory}, one named \source{match} and the other named
\source{rewrite}. An optional rule can be put in the same directory, in
a file called \source{rule}. See the [catalog directory
layout]{https://github.com/comby-tools/sample-catalog} for a [sample
catalog of templates]{https://catalog.comby.dev}.}
</div>
</div>
</div>
</section>
<!-- FAQ Section -->
<section class="page-section bg-secondary portfolio" id="faq">
<div class="container">
<!-- Section Heading -->
<h2 class="page-section-heading text-center">FAQ</h2>
<!-- Line -->
<div class="d-flex align-items-center flex-column">
<div class="divider-line"></div>
</div>
\h6{What about indentation-sensitive languages?}[what-about-python]
\p{Comby does not currently consider whitespace significant. We have plans
to support it though! The idea is that your declarative templates will
match on code that happens at the correct relative indentation level, for languages like Python.
Stay tuned! Of course, a lot of Python code is not sensitive to whitespace indentation, so Comby
is still useful (for example, a lot of Python 2 to Python 3 conversions will work in Comby).}
<!--
\h6{How does Comby compare to Regex?}[what-about-regex]
<!--https://stackoverflow.com/questions/133601/can-regular-expressions-be-used-to-match-nested-patterns}-->
<!--\h6{What about supporting Regex inside holes?}[language-support]-->
\p{More improvements coming soon!}
</section>
<!-- Copyright Section -->
<section class="copyright py-4 text-center text-white">
<div class="container">
<div class="row">
<div class="col-sm-12 text-center">
<a style="color: orange" href="https://twitter.com/rvtond"><i class="fab fa-twitter"></i>@rvtond</a>
</div>
<div class="col-sm-12 text-center">
<small>Copyright © 2019</small>
</div>
</div>
</div>
</section>
<!-- Scroll to Top Button (Only visible on small and extra-small screen sizes) -->
<div class="scroll-to-top d-lg-none position-fixed ">
<a class="js-scroll-trigger d-block text-center text-white rounded" href="#page-top">
<i class="fa fa-chevron-up"></i>
</a>
</div>
<!-- Bootstrap core JavaScript -->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Plugin JavaScript -->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for this template -->
<script src="js/freelancer.min.js"></script>
<script>
$(document).ready(function(){
// Add smooth scrolling to all links
$("a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
$('html, body').animate({
scrollTop: $(hash).offset().top
}, 800, function(){
// Add hash (#) to URL when done scrolling (default click behavior)
window.location.hash = hash;
});
} // End if
});
});
</script>
</body>
</html>