repper 1.0.0 → 1.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -1
- data/Gemfile +3 -1
- data/README.md +30 -16
- data/exe/repper +5 -0
- data/lib/repper/codemod.rb +70 -0
- data/lib/repper/command.rb +39 -0
- data/lib/repper/core_ext/regexp.rb +2 -0
- data/lib/repper/core_ext/regexp_ext.rb +1 -1
- data/lib/repper/format/annotated.rb +3 -2
- data/lib/repper/format/extended.rb +41 -0
- data/lib/repper/format/inline.rb +3 -2
- data/lib/repper/format/plain.rb +3 -2
- data/lib/repper/format/structured.rb +3 -2
- data/lib/repper/format/tabulo_style.rb +2 -2
- data/lib/repper/format.rb +2 -1
- data/lib/repper/token.rb +43 -0
- data/lib/repper/tokenizer.rb +44 -0
- data/lib/repper/version.rb +1 -1
- data/lib/repper.rb +12 -10
- data/repper.gemspec +2 -2
- data/repper.svg +176 -40
- metadata +14 -13
- data/lib/repper/element.rb +0 -31
- data/lib/repper/parser.rb +0 -49
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc27c0c06fc2947ca6485a0cbf9a904e83b959f5e05e5ae98d9441600d24c988
|
|
4
|
+
data.tar.gz: 0a597629326934ec23073f9729fa19eaa9e7f56e8ec11cd4573911039d36f908
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2041d9d7fc5f71e536c123f2274fe1353ba14d6c8b6fc01e63a1f45165618a94bd9268a9dd221eb8348f2c96a4ead548a383940ce986d5c8330ace7860c5f87b
|
|
7
|
+
data.tar.gz: bf2029e67d73116b47484304e20565c150179576d0645982c8433d3608cb8365e6f06860c9e820414c9d71d0abe9f239fb0b7ea97bd77a04b599ecfdac982d50
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
-
## [1.
|
|
3
|
+
## [1.1.1] - 2026-10-23
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- correct indentation when using newer `regexp_parser` versions
|
|
8
|
+
|
|
9
|
+
## [1.1.0] - 2022-05-29
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- codemod capability and corresponding `exe/repper` executable
|
|
14
|
+
- new format `Repper::Format::Extended`
|
|
15
|
+
- `Regexp#original_inspect` when using `Regexp#inspect` override
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- use the more appropriate `:inline` format when passing `format: nil | false`
|
|
20
|
+
|
|
21
|
+
## [1.0.0] - 2022-05-09
|
|
4
22
|
|
|
5
23
|
- Initial release
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
<
|
|
2
|
-
Repper
|
|
3
|
-
<img alt='Rapper necklace with dollar pendant' src='https://user-images.githubusercontent.com/10758879/167485870-5c49284d-a783-453e-8be0-a3597c2ef97c.png' height='46' align='right' />
|
|
4
|
-
</h1>
|
|
1
|
+
<img alt='Rapper necklace with dollar pendant' src='https://user-images.githubusercontent.com/10758879/167485870-5c49284d-a783-453e-8be0-a3597c2ef97c.png' height='64' align='right' />
|
|
5
2
|
|
|
6
|
-
Repper
|
|
3
|
+
# Repper
|
|
4
|
+
|
|
5
|
+
[](http://badge.fury.io/rb/repper)
|
|
6
|
+
[](https://github.com/jaynetics/repper/actions)
|
|
7
|
+
[](https://codecov.io/gh/jaynetics/repper)
|
|
8
|
+
|
|
9
|
+
Repper is a regular expression pretty printer and formatter for Ruby.
|
|
7
10
|
|
|
8
11
|
## Installation
|
|
9
12
|
|
|
@@ -11,20 +14,28 @@ Repper is a regular expression pretty printer for Ruby.
|
|
|
11
14
|
|
|
12
15
|
## Usage
|
|
13
16
|
|
|
14
|
-
`repper` can be integrated into the REPL (e.g. IRB) through core extensions or
|
|
17
|
+
`repper` can be integrated into the REPL (e.g. IRB) through core extensions for Regexp pretty-printing, integrated into editors to format Regexps, or called manually.
|
|
15
18
|
|
|
16
19
|
There are also a few customization options.
|
|
17
20
|
|
|
18
|
-
###
|
|
21
|
+
### REPL integration
|
|
22
|
+
|
|
23
|
+
#### Via Regexp#inspect (recommended)
|
|
19
24
|
|
|
20
25
|
`require 'repper/core_ext/regexp'` in your `~/.irbrc` or `~/.pryrc` to override `Regexp#inspect` and automatically use `repper` to display Regexps:
|
|
21
26
|
|
|
22
|
-
<img width="
|
|
27
|
+
<img width="475" alt="screenshot1" src="https://user-images.githubusercontent.com/10758879/167719748-60f4013a-c8d4-4a62-843a-d9f27057bcd3.png">
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
#### Via Kernel#pp
|
|
25
30
|
|
|
26
31
|
Alternatively, `require 'repper/core_ext/kernel'` to make the `pp` command give nicer output for Regexps (which will look like above by default).
|
|
27
32
|
|
|
33
|
+
### Editor integration
|
|
34
|
+
|
|
35
|
+
Use [vscode-repper](https://github.com/jaynetics/vscode-repper) to format Regexps in VSCode.
|
|
36
|
+
|
|
37
|
+

|
|
38
|
+
|
|
28
39
|
### Using Repper manually
|
|
29
40
|
|
|
30
41
|
```ruby
|
|
@@ -36,11 +47,13 @@ Repper.render(/foo/) # returns the pretty print String
|
|
|
36
47
|
|
|
37
48
|
#### Customizing the format
|
|
38
49
|
|
|
39
|
-
|
|
50
|
+
Multiple formats are available out of the box:
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
- `:annotated` is the default, verbose format, shown above
|
|
53
|
+
- `:inline` adds only colorization and does not restructure the Regexp
|
|
54
|
+
- `:structured` is like `:annotated`, just without annotations
|
|
55
|
+
- `:x` (or `:extended`) returns a lightly formatted but equivalent Regexp
|
|
56
|
+
- this format is used for the repper executable and [vscode-repper](https://github.com/jaynetics/vscode-repper)
|
|
44
57
|
|
|
45
58
|
You can change the format globally:
|
|
46
59
|
|
|
@@ -50,14 +63,14 @@ Repper.format = :structured
|
|
|
50
63
|
|
|
51
64
|
Or pick a format on a case-by-case basis:
|
|
52
65
|
|
|
53
|
-
<img width="
|
|
66
|
+
<img width="711" alt="screenshot2" src="https://user-images.githubusercontent.com/10758879/167719567-ae8ee42f-839e-4ce4-af56-a139044d3436.png">
|
|
54
67
|
|
|
55
68
|
Or create your own format:
|
|
56
69
|
|
|
57
70
|
```ruby
|
|
58
71
|
require 'csv'
|
|
59
72
|
|
|
60
|
-
csv_format = ->(
|
|
73
|
+
csv_format = ->(tokens, _theme) { tokens.map(&:text).to_csv }
|
|
61
74
|
Repper.render(/re[\p{pe}\r]$/, format: csv_format)
|
|
62
75
|
=> "/,re,[,\\p{pe},\\r,],$,/\n"
|
|
63
76
|
```
|
|
@@ -69,7 +82,8 @@ The color theme can also be set globally or passed on call:
|
|
|
69
82
|
```ruby
|
|
70
83
|
Repper.theme = :monokai # a nicer theme, if the terminal supports it
|
|
71
84
|
```
|
|
72
|
-
|
|
85
|
+
|
|
86
|
+
<img width="478" alt="screenshot3" src="https://user-images.githubusercontent.com/10758879/167719807-9170ba92-48d1-4669-a05d-a72f962b961d.png">
|
|
73
87
|
|
|
74
88
|
```ruby
|
|
75
89
|
Repper.call(/foo/, theme: nil) # render without colors
|
data/exe/repper
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Repper
|
|
2
|
+
# Formatter for Ruby code containing Regexp literals.
|
|
3
|
+
# Takes Ruby code, finds included Regexps (both // and %r style),
|
|
4
|
+
# formats them, and returns the updated Ruby code.
|
|
5
|
+
module Codemod
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def call(code)
|
|
9
|
+
formatted_code = code.dup
|
|
10
|
+
|
|
11
|
+
regexp_locations(code).reverse.each do |loc|
|
|
12
|
+
beg_idx = code[/\A(.*\n){#{loc.beg_line}}/].size + loc.beg_char
|
|
13
|
+
end_idx = code[/\A(.*\n){#{loc.end_line}}/].size + loc.end_char
|
|
14
|
+
range = beg_idx..end_idx
|
|
15
|
+
|
|
16
|
+
/\A(?<start>\/|%r.)(?<source>.*)(?<stop>[^a-z])(?<flags>[a-z]*)\z/m =~
|
|
17
|
+
code[range]
|
|
18
|
+
|
|
19
|
+
tokens = Tokenizer.call(source, delimiters: [start, stop], flags: flags)
|
|
20
|
+
formatted_regexp = Format::Extended.call(tokens, Theme::Plain)
|
|
21
|
+
|
|
22
|
+
# indent consistently by applying leading line indentation to all lines
|
|
23
|
+
lead_indentation = code.lines[loc.beg_line][/^ */]
|
|
24
|
+
formatted_regexp.gsub!("\n", "\n#{lead_indentation}")
|
|
25
|
+
|
|
26
|
+
formatted_code[range] = formatted_regexp
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
formatted_code
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
require 'ripper'
|
|
33
|
+
|
|
34
|
+
def regexp_locations(code)
|
|
35
|
+
embed_level = 0
|
|
36
|
+
beg_tokens = {}
|
|
37
|
+
|
|
38
|
+
Ripper.lex(code).each.with_object([]) do |token, acc|
|
|
39
|
+
case token[1]
|
|
40
|
+
when :on_regexp_beg
|
|
41
|
+
beg_tokens[embed_level] = token
|
|
42
|
+
# nested regexp literals are not supported a.t.m., so if we're
|
|
43
|
+
# in an embed, discard the location of the surrounding regexp.
|
|
44
|
+
beg_tokens[embed_level - 1] = nil
|
|
45
|
+
when :on_regexp_end
|
|
46
|
+
next unless beg_token = beg_tokens[embed_level]
|
|
47
|
+
|
|
48
|
+
acc << Location.new(
|
|
49
|
+
beg_line: beg_token[0][0] - 1, # note: using 0-indexed line values
|
|
50
|
+
beg_char: beg_token[0][1],
|
|
51
|
+
end_line: token[0][0] - 1,
|
|
52
|
+
end_char: token[0][1] + (token[2].length - 1), # lex includes flags
|
|
53
|
+
)
|
|
54
|
+
when :on_embexpr_beg # embedded expression a.k.a. interpolation (#{...})
|
|
55
|
+
embed_level += 1
|
|
56
|
+
when :on_embexpr_end
|
|
57
|
+
embed_level -= 1
|
|
58
|
+
when :on_const, :on_ident
|
|
59
|
+
# OK when embedded - Regexp::Parser will treat them as literals
|
|
60
|
+
else
|
|
61
|
+
# other embedded expressions are not supported
|
|
62
|
+
beg_tokens[embed_level - 1] = nil
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Location = Struct.new(:beg_line, :beg_char, :end_line, :end_char,
|
|
68
|
+
keyword_init: true)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Repper
|
|
2
|
+
# Service object for exe/repper. Formats Ruby code with Repper::Codemod.
|
|
3
|
+
module Command
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
PARSE_ERROR_EXIT_STATUS = 1
|
|
7
|
+
|
|
8
|
+
def call(argv)
|
|
9
|
+
if argv.count == 0
|
|
10
|
+
format_stdio
|
|
11
|
+
else
|
|
12
|
+
format_files(argv)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def format_stdio
|
|
17
|
+
input = STDIN.read
|
|
18
|
+
output = format(input)
|
|
19
|
+
print output
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def format(string)
|
|
23
|
+
Codemod.call(string)
|
|
24
|
+
rescue Repper::Error => e
|
|
25
|
+
warn "Parsing failed: #{e.class} - #{e.message}"
|
|
26
|
+
exit PARSE_ERROR_EXIT_STATUS
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def format_files(paths)
|
|
30
|
+
paths.grep(/\.rb\z/).each { |path| format_file(path) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format_file(path)
|
|
34
|
+
code = File.read(path)
|
|
35
|
+
formatted_code = format(code)
|
|
36
|
+
File.write(path, formatted_code)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module Repper
|
|
2
2
|
module Format
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# A structured and colorized format with annotations about token types.
|
|
4
|
+
Annotated = ->(tokens, theme) do
|
|
5
|
+
table = Tabulo::Table.new(tokens.reject(&:whitespace?), **TABULO_STYLE)
|
|
5
6
|
table.add_column(
|
|
6
7
|
:indented_text,
|
|
7
8
|
styler: ->(_, string, cell) { theme.colorize(string, cell.source.type) }
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Repper
|
|
2
|
+
module Format
|
|
3
|
+
# A lightly structured format that retains parsability
|
|
4
|
+
# and functional equivalence, for use in code.
|
|
5
|
+
Extended = ->(tokens, theme) do
|
|
6
|
+
run_types = %i[escape literal nonposixclass nonproperty
|
|
7
|
+
posixclass property set type]
|
|
8
|
+
forms_run = ->(el){ run_types.include?(el.type) || el.subtype == :dot }
|
|
9
|
+
prev = nil
|
|
10
|
+
|
|
11
|
+
tokens.each.with_object(''.dup) do |tok, acc|
|
|
12
|
+
# drop existing x-mode whitespace, if any
|
|
13
|
+
if tok.whitespace?
|
|
14
|
+
next
|
|
15
|
+
# keep some tokens in line:
|
|
16
|
+
# - option switches and conditions for syntactic correctness
|
|
17
|
+
# - quantifiers and codepoint runs for conciseness
|
|
18
|
+
elsif tok.type == :quantifier ||
|
|
19
|
+
tok.subtype == :options_switch && tok.text == ')' ||
|
|
20
|
+
tok.subtype == :condition ||
|
|
21
|
+
prev && forms_run.call(prev) && forms_run.call(tok)
|
|
22
|
+
acc << theme.colorize(tok.inlined_text, tok.type)
|
|
23
|
+
# keep comments in line, too, but with padding
|
|
24
|
+
elsif tok.comment?
|
|
25
|
+
acc << " #{theme.colorize(tok.inlined_text, tok.type)}"
|
|
26
|
+
# render root start, as well as end of empty root, without linebreak
|
|
27
|
+
elsif tok.root? && (prev.nil? || prev.root?)
|
|
28
|
+
acc << theme.colorize(tok.text, tok.type)
|
|
29
|
+
# else, if root is not empty, ensure x-flag is present at end
|
|
30
|
+
elsif tok.root?
|
|
31
|
+
acc << "\n#{theme.colorize(tok.text.sub(/x?\z/, 'x'), tok.type)}"
|
|
32
|
+
# render other tokens on their own lines for an indented structure,
|
|
33
|
+
# e.g. groups, alternations, anchors, assertions, ...
|
|
34
|
+
else
|
|
35
|
+
acc << "\n#{theme.colorize(tok.indented_text, tok.type)}"
|
|
36
|
+
end
|
|
37
|
+
prev = tok
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/repper/format/inline.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module Repper
|
|
2
2
|
module Format
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# A format that only adds color but does not change structure.
|
|
4
|
+
Inline = ->(tokens, theme) do
|
|
5
|
+
tokens.map { |tok| theme.colorize(tok.text, tok.type) }.join
|
|
5
6
|
end
|
|
6
7
|
end
|
|
7
8
|
end
|
data/lib/repper/format/plain.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module Repper
|
|
2
2
|
module Format
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# A structured format with colorization.
|
|
4
|
+
Structured = ->(tokens, theme) do
|
|
5
|
+
table = Tabulo::Table.new(tokens.reject(&:whitespace?), **TABULO_STYLE)
|
|
5
6
|
table.add_column(
|
|
6
7
|
:indented_text,
|
|
7
8
|
styler: ->(_, string, cell) { theme.colorize(string, cell.source.type) }
|
|
@@ -3,8 +3,8 @@ require 'tabulo'
|
|
|
3
3
|
module Repper
|
|
4
4
|
module Format
|
|
5
5
|
TABULO_STYLE = {
|
|
6
|
-
border: :blank,
|
|
7
|
-
header_frequency: nil,
|
|
6
|
+
border: :blank, # i.e. don't draw borders
|
|
7
|
+
header_frequency: nil, # i.e. omit column headers
|
|
8
8
|
truncation_indicator: '…',
|
|
9
9
|
wrap_body_cells_to: 1,
|
|
10
10
|
}
|
data/lib/repper/format.rb
CHANGED
|
@@ -3,8 +3,9 @@ module Repper
|
|
|
3
3
|
def self.cast(arg)
|
|
4
4
|
case arg
|
|
5
5
|
when ::Proc then arg
|
|
6
|
+
when :x then Format::Extended
|
|
6
7
|
when ::Symbol, ::String then Format.const_get(arg.capitalize) rescue nil
|
|
7
|
-
when false, nil then Format::
|
|
8
|
+
when false, nil then Format::Inline
|
|
8
9
|
end || raise(Repper::ArgumentError, "unknown format #{arg.inspect}")
|
|
9
10
|
end
|
|
10
11
|
end
|
data/lib/repper/token.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Repper
|
|
2
|
+
# A part of a Regexp. Generated by Repper::Tokenizer.
|
|
3
|
+
# `expression:` must be a Regexp::Expression::Base from regexp_parser.
|
|
4
|
+
Token = Struct.new(:expression, :text) do
|
|
5
|
+
def indented_text
|
|
6
|
+
"#{' ' * expression.nesting_level}#{inlined_text}"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def inlined_text
|
|
10
|
+
if comment?
|
|
11
|
+
text.strip
|
|
12
|
+
else
|
|
13
|
+
text
|
|
14
|
+
.gsub(/(?<!\\) /, '\\ ')
|
|
15
|
+
.gsub(/[\n\r\t\v]/) { |ws| ws.inspect.delete(?") }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def comment?
|
|
20
|
+
subtype == :comment
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def root?
|
|
24
|
+
subtype == :root
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def whitespace?
|
|
28
|
+
subtype == :whitespace
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def type
|
|
32
|
+
expression.type
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def subtype
|
|
36
|
+
expression.token
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def annotation
|
|
40
|
+
expression.human_name unless root?
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'regexp_parser'
|
|
2
|
+
|
|
3
|
+
module Repper
|
|
4
|
+
# Uses Regexp::Parser to get the AST of a Regexp, and turns that AST
|
|
5
|
+
# into a flat Array of visual elements that match the Regexp notation.
|
|
6
|
+
module Tokenizer
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def call(regexp, delimiters: ['/', '/'], flags: nil)
|
|
10
|
+
tree = Regexp::Parser.parse(regexp, options: flags =~ /x/ && Regexp::EXTENDED)
|
|
11
|
+
flatten(tree, delimiters: delimiters, flags: flags)
|
|
12
|
+
rescue ::Regexp::Parser::Error => e
|
|
13
|
+
raise e.extend(Repper::Error)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def flatten(exp, acc = [], delimiters: nil, flags: nil)
|
|
17
|
+
# Add opening entry.
|
|
18
|
+
exp.is?(:root) && acc << Token.new(exp, delimiters[0])
|
|
19
|
+
|
|
20
|
+
# Ignore nesting of invisible intermediate branches for better visuals.
|
|
21
|
+
if exp.is?(:sequence)
|
|
22
|
+
exp.each_expression(true) { |child| child.nesting_level -= 1 }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
exp.parts.each do |part|
|
|
26
|
+
if part.instance_of?(::String)
|
|
27
|
+
acc << Token.new(exp, part)
|
|
28
|
+
else # part.is_a?(Regexp::Expression::Base)
|
|
29
|
+
flatten(part, acc)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
exp.quantified? && flatten(exp.quantifier, acc)
|
|
34
|
+
|
|
35
|
+
# Add closing entry.
|
|
36
|
+
exp.is?(:root) && begin
|
|
37
|
+
flags ||= exp.options.keys.join
|
|
38
|
+
acc << Token.new(exp, "#{delimiters[1]}#{flags.chars.uniq.sort.join}")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
acc
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/repper/version.rb
CHANGED
data/lib/repper.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
require_relative "repper/
|
|
1
|
+
require_relative "repper/codemod"
|
|
2
|
+
require_relative "repper/command"
|
|
2
3
|
require_relative "repper/errors"
|
|
3
4
|
require_relative "repper/format"
|
|
4
|
-
require_relative "repper/
|
|
5
|
+
require_relative "repper/token"
|
|
6
|
+
require_relative "repper/tokenizer"
|
|
5
7
|
require_relative "repper/theme"
|
|
6
8
|
require_relative "repper/version"
|
|
7
9
|
|
|
@@ -14,18 +16,18 @@ module Repper
|
|
|
14
16
|
end
|
|
15
17
|
|
|
16
18
|
def render(regexp, format: self.format, theme: self.theme)
|
|
17
|
-
|
|
18
|
-
format
|
|
19
|
-
theme
|
|
20
|
-
format.call(
|
|
19
|
+
tokens = Tokenizer.call(regexp)
|
|
20
|
+
format = Format.cast(format)
|
|
21
|
+
theme = Theme.cast(theme)
|
|
22
|
+
format.call(tokens, theme)
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
def
|
|
24
|
-
@
|
|
25
|
+
def format=(arg)
|
|
26
|
+
@format = Format.cast(arg)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
def
|
|
28
|
-
@
|
|
29
|
+
def theme=(arg)
|
|
30
|
+
@theme = Theme.cast(arg)
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
data/repper.gemspec
CHANGED
|
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.authors = ["Janosch Müller"]
|
|
7
7
|
spec.email = ["janosch84@gmail.com"]
|
|
8
8
|
|
|
9
|
-
spec.summary = "Regexp pretty printer for Ruby"
|
|
9
|
+
spec.summary = "Regexp pretty printer and formatter for Ruby"
|
|
10
10
|
spec.homepage = "https://github.com/jaynetics/repper"
|
|
11
11
|
spec.license = "MIT"
|
|
12
12
|
spec.required_ruby_version = ">= 2.7.0"
|
|
@@ -25,6 +25,6 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.require_paths = ["lib"]
|
|
26
26
|
|
|
27
27
|
spec.add_dependency "rainbow", "~> 3.1"
|
|
28
|
-
spec.add_dependency "regexp_parser", "~> 2.
|
|
28
|
+
spec.add_dependency "regexp_parser", "~> 2.6"
|
|
29
29
|
spec.add_dependency "tabulo", "~> 2.8"
|
|
30
30
|
end
|
data/repper.svg
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
id="svg5"
|
|
10
10
|
inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
|
|
11
11
|
sodipodi:docname="repper.svg"
|
|
12
|
+
inkscape:export-xdpi="32.537697"
|
|
13
|
+
inkscape:export-ydpi="32.537697"
|
|
12
14
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
13
15
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
14
16
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -24,16 +26,78 @@
|
|
|
24
26
|
inkscape:document-units="mm"
|
|
25
27
|
showgrid="false"
|
|
26
28
|
inkscape:zoom="0.3"
|
|
27
|
-
inkscape:cx="
|
|
29
|
+
inkscape:cx="178.33333"
|
|
28
30
|
inkscape:cy="400"
|
|
29
31
|
inkscape:window-width="1383"
|
|
30
32
|
inkscape:window-height="916"
|
|
31
|
-
inkscape:window-x="
|
|
32
|
-
inkscape:window-y="
|
|
33
|
+
inkscape:window-x="1512"
|
|
34
|
+
inkscape:window-y="496"
|
|
33
35
|
inkscape:window-maximized="0"
|
|
34
36
|
inkscape:current-layer="layer1" />
|
|
35
37
|
<defs
|
|
36
38
|
id="defs2">
|
|
39
|
+
<inkscape:path-effect
|
|
40
|
+
effect="skeletal"
|
|
41
|
+
id="path-effect92594"
|
|
42
|
+
is_visible="true"
|
|
43
|
+
lpeversion="1"
|
|
44
|
+
pattern="m 218.50956,-4.9822433 c -1.39261,-1.458531 -5.24307,-0.392108 -8.59476,2.3804213 -3.3517,2.77251917 -4.94168,6.2064186 -3.54907,7.6649479 1.39261,1.4585306 5.24306,0.3921075 8.59476,-2.3804211 3.35169,-2.77251913 4.94168,-6.206419 3.54907,-7.6649481 z"
|
|
45
|
+
copytype="single_stretched"
|
|
46
|
+
prop_scale="1"
|
|
47
|
+
scale_y_rel="false"
|
|
48
|
+
spacing="0"
|
|
49
|
+
normal_offset="0"
|
|
50
|
+
tang_offset="0"
|
|
51
|
+
prop_units="false"
|
|
52
|
+
vertical_pattern="false"
|
|
53
|
+
hide_knot="false"
|
|
54
|
+
fuse_tolerance="0" />
|
|
55
|
+
<inkscape:path-effect
|
|
56
|
+
effect="simplify"
|
|
57
|
+
id="path-effect92590"
|
|
58
|
+
is_visible="true"
|
|
59
|
+
lpeversion="1"
|
|
60
|
+
steps="1"
|
|
61
|
+
threshold="0.00221557"
|
|
62
|
+
smooth_angles="360"
|
|
63
|
+
helper_size="0"
|
|
64
|
+
simplify_individual_paths="false"
|
|
65
|
+
simplify_just_coalesce="false" />
|
|
66
|
+
<inkscape:path-effect
|
|
67
|
+
effect="skeletal"
|
|
68
|
+
id="path-effect92556"
|
|
69
|
+
is_visible="true"
|
|
70
|
+
lpeversion="1"
|
|
71
|
+
pattern="m -6.5579804,-4.9666732 c 1.392609,-1.4585305 5.243064,-0.3921075 8.59476,2.3804215 3.351699,2.77251918 4.941681,6.2064186 3.54907,7.6649479 -1.39261,1.4585306 -5.24306404,0.3921075 -8.594759,-2.3804211 -3.351699,-2.77251912 -4.941682,-6.206419 -3.549071,-7.6649483 z"
|
|
72
|
+
copytype="single_stretched"
|
|
73
|
+
prop_scale="1"
|
|
74
|
+
scale_y_rel="false"
|
|
75
|
+
spacing="0"
|
|
76
|
+
normal_offset="0"
|
|
77
|
+
tang_offset="0"
|
|
78
|
+
prop_units="false"
|
|
79
|
+
vertical_pattern="false"
|
|
80
|
+
hide_knot="false"
|
|
81
|
+
fuse_tolerance="0" />
|
|
82
|
+
<inkscape:path-effect
|
|
83
|
+
effect="simplify"
|
|
84
|
+
id="path-effect92552"
|
|
85
|
+
is_visible="true"
|
|
86
|
+
lpeversion="1"
|
|
87
|
+
steps="1"
|
|
88
|
+
threshold="0.00221557"
|
|
89
|
+
smooth_angles="360"
|
|
90
|
+
helper_size="0"
|
|
91
|
+
simplify_individual_paths="false"
|
|
92
|
+
simplify_just_coalesce="false" />
|
|
93
|
+
<linearGradient
|
|
94
|
+
id="linearGradient91990"
|
|
95
|
+
inkscape:swatch="solid">
|
|
96
|
+
<stop
|
|
97
|
+
style="stop-color:#e3cf00;stop-opacity:1;"
|
|
98
|
+
offset="0"
|
|
99
|
+
id="stop91988" />
|
|
100
|
+
</linearGradient>
|
|
37
101
|
<inkscape:path-effect
|
|
38
102
|
effect="skeletal"
|
|
39
103
|
id="path-effect43053"
|
|
@@ -304,6 +368,60 @@
|
|
|
304
368
|
vertical_pattern="false"
|
|
305
369
|
hide_knot="false"
|
|
306
370
|
fuse_tolerance="0" />
|
|
371
|
+
<inkscape:path-effect
|
|
372
|
+
effect="simplify"
|
|
373
|
+
id="path-effect29027-15"
|
|
374
|
+
is_visible="true"
|
|
375
|
+
lpeversion="1"
|
|
376
|
+
steps="1"
|
|
377
|
+
threshold="0.00221557"
|
|
378
|
+
smooth_angles="360"
|
|
379
|
+
helper_size="0"
|
|
380
|
+
simplify_individual_paths="false"
|
|
381
|
+
simplify_just_coalesce="false" />
|
|
382
|
+
<inkscape:path-effect
|
|
383
|
+
effect="skeletal"
|
|
384
|
+
id="path-effect29029-2"
|
|
385
|
+
is_visible="true"
|
|
386
|
+
lpeversion="1"
|
|
387
|
+
pattern="m 20.669672,46.003934 c 0.621589,-1.918412 4.553331,-2.628809 8.77621,-1.585706 4.222877,1.043101 7.145659,3.446649 6.524067,5.365061 -0.62159,1.918412 -4.553331,2.628807 -8.776209,1.585705 -4.222877,-1.043101 -7.14566,-3.446649 -6.524068,-5.36506 z"
|
|
388
|
+
copytype="single_stretched"
|
|
389
|
+
prop_scale="1"
|
|
390
|
+
scale_y_rel="false"
|
|
391
|
+
spacing="0"
|
|
392
|
+
normal_offset="0"
|
|
393
|
+
tang_offset="0"
|
|
394
|
+
prop_units="false"
|
|
395
|
+
vertical_pattern="false"
|
|
396
|
+
hide_knot="false"
|
|
397
|
+
fuse_tolerance="0" />
|
|
398
|
+
<inkscape:path-effect
|
|
399
|
+
effect="simplify"
|
|
400
|
+
id="path-effect92552-3"
|
|
401
|
+
is_visible="true"
|
|
402
|
+
lpeversion="1"
|
|
403
|
+
steps="1"
|
|
404
|
+
threshold="0.00221557"
|
|
405
|
+
smooth_angles="360"
|
|
406
|
+
helper_size="0"
|
|
407
|
+
simplify_individual_paths="false"
|
|
408
|
+
simplify_just_coalesce="false" />
|
|
409
|
+
<inkscape:path-effect
|
|
410
|
+
effect="skeletal"
|
|
411
|
+
id="path-effect92556-9"
|
|
412
|
+
is_visible="true"
|
|
413
|
+
lpeversion="1"
|
|
414
|
+
pattern="m -6.5579804,-4.9666732 c 1.392609,-1.4585305 5.243064,-0.3921075 8.59476,2.3804215 3.351699,2.77251918 4.941681,6.2064186 3.54907,7.6649479 -1.39261,1.4585306 -5.24306404,0.3921075 -8.594759,-2.3804211 -3.351699,-2.77251912 -4.941682,-6.206419 -3.549071,-7.6649483 z"
|
|
415
|
+
copytype="single_stretched"
|
|
416
|
+
prop_scale="1"
|
|
417
|
+
scale_y_rel="false"
|
|
418
|
+
spacing="0"
|
|
419
|
+
normal_offset="0"
|
|
420
|
+
tang_offset="0"
|
|
421
|
+
prop_units="false"
|
|
422
|
+
vertical_pattern="false"
|
|
423
|
+
hide_knot="false"
|
|
424
|
+
fuse_tolerance="0" />
|
|
307
425
|
</defs>
|
|
308
426
|
<g
|
|
309
427
|
inkscape:label="Ebene 1"
|
|
@@ -311,136 +429,154 @@
|
|
|
311
429
|
id="layer1">
|
|
312
430
|
<text
|
|
313
431
|
xml:space="preserve"
|
|
314
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
432
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
315
433
|
x="88.609558"
|
|
316
434
|
y="142.00261"
|
|
317
|
-
id="text473"
|
|
435
|
+
id="text473"
|
|
436
|
+
inkscape:export-xdpi="32.30674"
|
|
437
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
318
438
|
sodipodi:role="line"
|
|
319
439
|
id="tspan471"
|
|
320
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
440
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
321
441
|
x="88.609558"
|
|
322
442
|
y="142.00261">$</tspan></text>
|
|
323
443
|
<text
|
|
324
444
|
xml:space="preserve"
|
|
325
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
445
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
326
446
|
x="26.48514"
|
|
327
447
|
y="147.63461"
|
|
328
448
|
id="text473-4"
|
|
329
449
|
inkscape:transform-center-x="2.9956772"
|
|
330
450
|
inkscape:transform-center-y="-2.5677233"><tspan
|
|
331
451
|
id="tspan471-3"
|
|
332
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
452
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:50.8px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
333
453
|
x="26.48514"
|
|
334
454
|
y="147.63461"
|
|
335
455
|
sodipodi:role="line" /></text>
|
|
336
456
|
<text
|
|
337
457
|
xml:space="preserve"
|
|
338
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.7622px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
458
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.7622px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
339
459
|
x="84.480263"
|
|
340
460
|
y="-73.830437"
|
|
341
461
|
id="text473-1"
|
|
342
|
-
transform="matrix(-0.01039371,0.84174345,-1.1879195,-0.00736484,0,0)"
|
|
462
|
+
transform="matrix(-0.01039371,0.84174345,-1.1879195,-0.00736484,0,0)"
|
|
463
|
+
inkscape:export-xdpi="32.30674"
|
|
464
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
343
465
|
sodipodi:role="line"
|
|
344
466
|
id="tspan471-8"
|
|
345
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.7622px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
467
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.7622px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
346
468
|
x="84.480263"
|
|
347
469
|
y="-73.830437">0</tspan></text>
|
|
348
470
|
<text
|
|
349
471
|
xml:space="preserve"
|
|
350
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:44.4055px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';white-space:pre;inline-size:40.7295;stroke-width:
|
|
472
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:44.4055px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';white-space:pre;inline-size:40.7295;fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.53487;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
351
473
|
x="18.91221"
|
|
352
474
|
y="-47.323662"
|
|
353
475
|
id="text473-1-5"
|
|
354
|
-
transform="matrix(-0.45969555,0.66650243,-0.97588205,-0.53512053,4.2333335,10.289189)"
|
|
476
|
+
transform="matrix(-0.45969555,0.66650243,-0.97588205,-0.53512053,4.2333335,10.289189)"
|
|
477
|
+
inkscape:export-xdpi="32.30674"
|
|
478
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
355
479
|
x="18.91221"
|
|
356
480
|
y="-47.323662"
|
|
357
|
-
id="
|
|
481
|
+
id="tspan93379">0</tspan></text>
|
|
358
482
|
<text
|
|
359
483
|
xml:space="preserve"
|
|
360
|
-
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';stroke-width:
|
|
484
|
+
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
361
485
|
x="47.930836"
|
|
362
486
|
y="84.734871"
|
|
363
487
|
id="text18132"><tspan
|
|
364
488
|
sodipodi:role="line"
|
|
365
489
|
id="tspan18130"
|
|
366
|
-
style="stroke-width:
|
|
490
|
+
style="fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
367
491
|
x="47.930836"
|
|
368
492
|
y="84.734871" /></text>
|
|
369
493
|
<text
|
|
370
494
|
xml:space="preserve"
|
|
371
|
-
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';stroke-width:
|
|
495
|
+
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
372
496
|
x="35.948128"
|
|
373
497
|
y="33.380402"
|
|
374
498
|
id="text23204"><tspan
|
|
375
499
|
sodipodi:role="line"
|
|
376
500
|
id="tspan23202"
|
|
377
|
-
style="stroke-width:
|
|
501
|
+
style="fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
378
502
|
x="35.948128"
|
|
379
503
|
y="33.380402" /></text>
|
|
380
504
|
<path
|
|
381
|
-
style="fill:#
|
|
382
|
-
d="m 59.
|
|
505
|
+
style="fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
506
|
+
d="m 59.099139,70.776137 c 2.12787,-1.081793 10.854698,1.976966 20.364006,5.139528 -0.108589,-0.03622 1.244719,0.415606 1.13613,0.379383 9.989564,3.340372 17.61416,6.281333 15.582842,8.12586 -1.591933,1.445551 -9.462126,1.32328 -18.440304,-1.306619 0,-10e-7 -10e-7,-10e-7 -10e-7,-10e-7 C 76.245556,82.674336 74.739206,82.162967 73.238054,81.580609 62.45744,77.398376 57.087976,71.798591 59.099139,70.776137 Z"
|
|
383
507
|
id="path29025"
|
|
384
508
|
inkscape:path-effect="#path-effect29027;#path-effect29029"
|
|
385
509
|
inkscape:original-d="m 58.148912,72.423541 c 13.62864,5.908708 23.245218,8.103634 38.499876,10.153486"
|
|
386
|
-
sodipodi:nodetypes="cc"
|
|
510
|
+
sodipodi:nodetypes="cc"
|
|
511
|
+
inkscape:export-xdpi="32.30674"
|
|
512
|
+
inkscape:export-ydpi="32.30674" />
|
|
387
513
|
<text
|
|
388
514
|
xml:space="preserve"
|
|
389
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.0429px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
515
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.0429px;line-height:1;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
390
516
|
x="146.16597"
|
|
391
517
|
y="96.452888"
|
|
392
518
|
id="text473-1-5-0"
|
|
393
|
-
transform="matrix(0.4855282,0.70395662,1.0307219,-0.5651917,0,0)"
|
|
519
|
+
transform="matrix(0.4855282,0.70395662,1.0307219,-0.5651917,0,0)"
|
|
520
|
+
inkscape:export-xdpi="32.30674"
|
|
521
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
394
522
|
sodipodi:role="line"
|
|
395
523
|
id="tspan471-8-6-1"
|
|
396
|
-
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.0429px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';stroke-width:
|
|
524
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:42.0429px;font-family:Thonburi;-inkscape-font-specification:'Thonburi Bold';fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
397
525
|
x="146.16597"
|
|
398
526
|
y="96.452888">0</tspan></text>
|
|
399
527
|
<path
|
|
400
|
-
style="fill:#
|
|
401
|
-
d="m 115.94486,85.
|
|
528
|
+
style="fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
529
|
+
d="m 115.94486,85.097146 c 1.62012,1.508092 9.59184,1.369553 18.63551,-1.408796 0,0 0,0 0,0 1.46199,-0.451029 2.93133,-0.972313 4.39362,-1.563218 10.78546,-4.358378 16.03219,-10.151702 13.97774,-11.205664 -2.17642,-1.116557 -10.72491,1.99989 -20.23992,5.297849 0.14949,-0.05199 -1.38801,0.483186 -1.23853,0.431194 -9.95842,3.471909 -17.58669,6.532679 -15.52842,8.448635 z"
|
|
402
530
|
id="path29025-0"
|
|
403
531
|
sodipodi:nodetypes="cc"
|
|
404
532
|
inkscape:original-d="m 153.95732,72.621585 c -13.62872,6.144952 -23.24535,8.427629 -38.50001,10.55943"
|
|
405
|
-
inkscape:path-effect="#path-effect43049;#path-effect43053"
|
|
533
|
+
inkscape:path-effect="#path-effect43049;#path-effect43053"
|
|
534
|
+
inkscape:export-xdpi="32.30674"
|
|
535
|
+
inkscape:export-ydpi="32.30674" />
|
|
406
536
|
<text
|
|
407
537
|
xml:space="preserve"
|
|
408
|
-
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';stroke-width:
|
|
538
|
+
style="font-size:10.5833px;line-height:1.25;font-family:'System Font';-inkscape-font-specification:'System Font';fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
409
539
|
x="67.616714"
|
|
410
540
|
y="123.67867"
|
|
411
541
|
id="text30077"><tspan
|
|
412
542
|
sodipodi:role="line"
|
|
413
543
|
id="tspan30075"
|
|
414
|
-
style="stroke-width:
|
|
544
|
+
style="fill:#e9c915;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
415
545
|
x="67.616714"
|
|
416
546
|
y="123.67867" /></text>
|
|
417
547
|
<rect
|
|
418
548
|
id="rect66881"
|
|
419
|
-
width="
|
|
420
|
-
height="
|
|
421
|
-
x="102.
|
|
422
|
-
y="
|
|
423
|
-
style="stroke-width:
|
|
549
|
+
width="7.2900386"
|
|
550
|
+
height="11.079004"
|
|
551
|
+
x="102.50966"
|
|
552
|
+
y="87.608177"
|
|
553
|
+
style="fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.05246;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
554
|
+
inkscape:export-xdpi="32.30674"
|
|
555
|
+
inkscape:export-ydpi="32.30674" />
|
|
424
556
|
<text
|
|
425
557
|
xml:space="preserve"
|
|
426
|
-
style="font-size:31.75px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:
|
|
558
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.75px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
427
559
|
x="72.62812"
|
|
428
560
|
y="153.12755"
|
|
429
|
-
id="text75927"
|
|
561
|
+
id="text75927"
|
|
562
|
+
inkscape:export-xdpi="32.30674"
|
|
563
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
430
564
|
sodipodi:role="line"
|
|
431
565
|
id="tspan75925"
|
|
432
|
-
style="font-size:31.75px;
|
|
566
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.75px;font-family:Arial;-inkscape-font-specification:Arial;fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
433
567
|
x="72.62812"
|
|
434
568
|
y="153.12755">*</tspan></text>
|
|
435
569
|
<text
|
|
436
570
|
xml:space="preserve"
|
|
437
|
-
style="font-size:31.75px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:
|
|
571
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.75px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
438
572
|
x="124.74483"
|
|
439
573
|
y="125.85077"
|
|
440
|
-
id="text75927-8"
|
|
574
|
+
id="text75927-8"
|
|
575
|
+
inkscape:export-xdpi="32.30674"
|
|
576
|
+
inkscape:export-ydpi="32.30674"><tspan
|
|
441
577
|
sodipodi:role="line"
|
|
442
578
|
id="tspan75925-9"
|
|
443
|
-
style="font-size:31.75px;
|
|
579
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:31.75px;font-family:Arial;-inkscape-font-specification:Arial;fill:#efc30f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
|
444
580
|
x="124.74483"
|
|
445
581
|
y="125.85077">*</tspan></text>
|
|
446
582
|
</g>
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: repper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janosch Müller
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rainbow
|
|
@@ -30,14 +29,14 @@ dependencies:
|
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.
|
|
32
|
+
version: '2.6'
|
|
34
33
|
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '2.
|
|
39
|
+
version: '2.6'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
41
|
name: tabulo
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,10 +51,10 @@ dependencies:
|
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '2.8'
|
|
55
|
-
description:
|
|
56
54
|
email:
|
|
57
55
|
- janosch84@gmail.com
|
|
58
|
-
executables:
|
|
56
|
+
executables:
|
|
57
|
+
- repper
|
|
59
58
|
extensions: []
|
|
60
59
|
extra_rdoc_files: []
|
|
61
60
|
files:
|
|
@@ -65,24 +64,28 @@ files:
|
|
|
65
64
|
- LICENSE.txt
|
|
66
65
|
- README.md
|
|
67
66
|
- Rakefile
|
|
67
|
+
- exe/repper
|
|
68
68
|
- lib/repper.rb
|
|
69
|
+
- lib/repper/codemod.rb
|
|
70
|
+
- lib/repper/command.rb
|
|
69
71
|
- lib/repper/core_ext/kernel.rb
|
|
70
72
|
- lib/repper/core_ext/kernel_ext.rb
|
|
71
73
|
- lib/repper/core_ext/regexp.rb
|
|
72
74
|
- lib/repper/core_ext/regexp_ext.rb
|
|
73
|
-
- lib/repper/element.rb
|
|
74
75
|
- lib/repper/errors.rb
|
|
75
76
|
- lib/repper/format.rb
|
|
76
77
|
- lib/repper/format/annotated.rb
|
|
78
|
+
- lib/repper/format/extended.rb
|
|
77
79
|
- lib/repper/format/inline.rb
|
|
78
80
|
- lib/repper/format/plain.rb
|
|
79
81
|
- lib/repper/format/structured.rb
|
|
80
82
|
- lib/repper/format/tabulo_style.rb
|
|
81
|
-
- lib/repper/parser.rb
|
|
82
83
|
- lib/repper/theme.rb
|
|
83
84
|
- lib/repper/theme/default.rb
|
|
84
85
|
- lib/repper/theme/monokai.rb
|
|
85
86
|
- lib/repper/theme/plain.rb
|
|
87
|
+
- lib/repper/token.rb
|
|
88
|
+
- lib/repper/tokenizer.rb
|
|
86
89
|
- lib/repper/version.rb
|
|
87
90
|
- repper.gemspec
|
|
88
91
|
- repper.svg
|
|
@@ -94,7 +97,6 @@ metadata:
|
|
|
94
97
|
homepage_uri: https://github.com/jaynetics/repper
|
|
95
98
|
source_code_uri: https://github.com/jaynetics/repper
|
|
96
99
|
changelog_uri: https://github.com/jaynetics/repper/tree/main/CHANGELOG.md
|
|
97
|
-
post_install_message:
|
|
98
100
|
rdoc_options: []
|
|
99
101
|
require_paths:
|
|
100
102
|
- lib
|
|
@@ -109,8 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
109
111
|
- !ruby/object:Gem::Version
|
|
110
112
|
version: '0'
|
|
111
113
|
requirements: []
|
|
112
|
-
rubygems_version:
|
|
113
|
-
signing_key:
|
|
114
|
+
rubygems_version: 4.0.23
|
|
114
115
|
specification_version: 4
|
|
115
|
-
summary: Regexp pretty printer for Ruby
|
|
116
|
+
summary: Regexp pretty printer and formatter for Ruby
|
|
116
117
|
test_files: []
|
data/lib/repper/element.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
module Repper
|
|
2
|
-
Element = Struct.new(:type, :subtype, :level, :text, :id, keyword_init: true) do
|
|
3
|
-
def indented_text
|
|
4
|
-
inlined_text = text.gsub(/[\n\r\t\v]/) { |ws| ws.inspect.delete(?") }
|
|
5
|
-
"#{' ' * level}#{inlined_text}"
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def whitespace?
|
|
9
|
-
subtype == :whitespace
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def annotation
|
|
13
|
-
case [type, subtype]
|
|
14
|
-
in [_, :root]
|
|
15
|
-
nil
|
|
16
|
-
in [_, :alternation | :comment | :condition | :intersection | :range => subtype]
|
|
17
|
-
subtype
|
|
18
|
-
in [:conditional | :free_space => type, _]
|
|
19
|
-
type
|
|
20
|
-
in [:group, :capture | :named]
|
|
21
|
-
"capture group #{id}"
|
|
22
|
-
in [:meta, :dot]
|
|
23
|
-
'match-all'
|
|
24
|
-
in [:keep, :mark]
|
|
25
|
-
'keep-mark lookbehind'
|
|
26
|
-
in [type, subtype]
|
|
27
|
-
[subtype, type].uniq.join(' ')
|
|
28
|
-
end.to_s.tr('_', ' ')
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
data/lib/repper/parser.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require 'regexp_parser'
|
|
2
|
-
|
|
3
|
-
module Repper
|
|
4
|
-
module Parser
|
|
5
|
-
module_function
|
|
6
|
-
|
|
7
|
-
def call(regexp)
|
|
8
|
-
tree = ::Regexp::Parser.parse(regexp)
|
|
9
|
-
flatten(tree)
|
|
10
|
-
rescue ::Regexp::Parser::Error => e
|
|
11
|
-
raise e.extend(Repper::Error)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Turn Regexp::Parser AST back into a flat Array of visual elements
|
|
15
|
-
# that match the Regexp notation.
|
|
16
|
-
def flatten(exp, acc = [])
|
|
17
|
-
# Add opening entry.
|
|
18
|
-
exp.is?(:root) && acc << make_element(exp, '/')
|
|
19
|
-
|
|
20
|
-
# Ignore nesting of invisible intermediate branches for better visuals.
|
|
21
|
-
exp.is?(:sequence) && exp.nesting_level -= 1
|
|
22
|
-
|
|
23
|
-
exp.parts.each do |part|
|
|
24
|
-
if part.instance_of?(::String)
|
|
25
|
-
acc << make_element(exp, part)
|
|
26
|
-
else # part.is_a?(Regexp::Expression::Base)
|
|
27
|
-
flatten(part, acc)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
exp.quantified? && flatten(exp.quantifier, acc)
|
|
32
|
-
|
|
33
|
-
# Add closing entry.
|
|
34
|
-
exp.is?(:root) && acc << make_element(exp, "/#{exp.options.keys.join}")
|
|
35
|
-
|
|
36
|
-
acc
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def make_element(exp, text)
|
|
40
|
-
Element.new(
|
|
41
|
-
type: exp.type,
|
|
42
|
-
subtype: exp.token,
|
|
43
|
-
level: exp.nesting_level,
|
|
44
|
-
text: text,
|
|
45
|
-
id: exp.respond_to?(:identifier) && exp.identifier,
|
|
46
|
-
)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|