syntax_search 0.2.0 → 0.2.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/.gitignore +1 -0
- data/CHANGELOG.md +2 -29
- data/Gemfile.lock +3 -1
- data/exe/syntax_search +5 -71
- data/lib/syntax_search/auto.rb +5 -49
- data/syntax_search.gemspec +3 -3
- metadata +17 -19
- data/lib/syntax_search.rb +0 -145
- data/lib/syntax_search/around_block_scan.rb +0 -193
- data/lib/syntax_search/block_expand.rb +0 -74
- data/lib/syntax_search/capture_code_context.rb +0 -62
- data/lib/syntax_search/code_block.rb +0 -78
- data/lib/syntax_search/code_frontier.rb +0 -151
- data/lib/syntax_search/code_line.rb +0 -128
- data/lib/syntax_search/code_search.rb +0 -154
- data/lib/syntax_search/display_code_with_line_numbers.rb +0 -56
- data/lib/syntax_search/display_invalid_blocks.rb +0 -100
- data/lib/syntax_search/fyi.rb +0 -7
- data/lib/syntax_search/heredoc_block_parse.rb +0 -30
- data/lib/syntax_search/lex_all.rb +0 -58
- data/lib/syntax_search/parse_blocks_from_indent_line.rb +0 -56
- data/lib/syntax_search/version.rb +0 -5
- data/lib/syntax_search/who_dis_syntax_error.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 739770be9259abf88e8ea3c7dc1223e279cc79ab35d907312b0cc268d00363ed
|
4
|
+
data.tar.gz: ca7fbab5999100db76c5758f3f920fc7f91872d678b028157761cd6b72e348d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60c1aea7c3f075f0486d85e72bc4761879efd09d5805c6581efa21765c78edd335f172094dcc961f77e00f1bf4e0867f8382b32e7d13e2de248085679e3728e6
|
7
|
+
data.tar.gz: adf40fe0011de00194eef22b5f4caa86196f0b8bf1439c8d48a7f3fbe465521ab04bf856f9cd20407dace52ab154cf1c27d0a519c00d15e862e6100322f2c4f2
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,32 +1,5 @@
|
|
1
1
|
## HEAD (unreleased)
|
2
2
|
|
3
|
-
## 0.2.
|
3
|
+
## 0.2.1
|
4
4
|
|
5
|
-
|
6
|
-
- Block expansion is now lexically aware of keywords (def/do/end etc.) (https://github.com/zombocom/syntax_search/pull/24)
|
7
|
-
- Fix bug where not all of a source is lexed which is used in heredoc detection/removal (https://github.com/zombocom/syntax_search/pull/23)
|
8
|
-
|
9
|
-
## 0.1.5
|
10
|
-
|
11
|
-
- Strip out heredocs in documents first (https://github.com/zombocom/syntax_search/pull/19)
|
12
|
-
|
13
|
-
## 0.1.4
|
14
|
-
|
15
|
-
- Parser gem replaced with Ripper (https://github.com/zombocom/syntax_search/pull/17)
|
16
|
-
|
17
|
-
## 0.1.3
|
18
|
-
|
19
|
-
- Internal refactor (https://github.com/zombocom/syntax_search/pull/13)
|
20
|
-
|
21
|
-
## 0.1.2
|
22
|
-
|
23
|
-
- Codeblocks in output are now indented with 4 spaces and "code fences" are removed (https://github.com/zombocom/syntax_search/pull/11)
|
24
|
-
- "Unmatched end" and "missing end" not generate different error text instructions (https://github.com/zombocom/syntax_search/pull/10)
|
25
|
-
|
26
|
-
## 0.1.1
|
27
|
-
|
28
|
-
- Fire search on both unexpected end-of-input and unexected end (https://github.com/zombocom/syntax_search/pull/8)
|
29
|
-
|
30
|
-
## 0.1.0
|
31
|
-
|
32
|
-
- Initial release
|
5
|
+
This gem is moved to the `dead_end` gem. Please use that instead
|
data/Gemfile.lock
CHANGED
data/exe/syntax_search
CHANGED
@@ -1,74 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
warn "syntax_search gem is deprecated please use `dead_end` instead"
|
4
|
+
warn
|
5
|
+
warn " $ gem install dead_end`"
|
6
|
+
warn
|
6
7
|
|
7
|
-
|
8
|
-
options[:terminal] = true
|
9
|
-
options[:record_dir] = ENV["SYNTAX_SEARCH_RECORD_DIR"]
|
10
|
-
|
11
|
-
parser = OptionParser.new do |opts|
|
12
|
-
opts.banner = <<~EOM
|
13
|
-
Usage: syntax_search <file> [options]
|
14
|
-
|
15
|
-
Parses a ruby source file and searches for syntax error(s) unexpected `end', expecting end-of-input.
|
16
|
-
|
17
|
-
Example:
|
18
|
-
|
19
|
-
$ syntax_search dog.rb
|
20
|
-
|
21
|
-
# ...
|
22
|
-
|
23
|
-
```
|
24
|
-
1 require 'animals'
|
25
|
-
2
|
26
|
-
❯ 10 defdog
|
27
|
-
❯ 15 end
|
28
|
-
❯ 16
|
29
|
-
20 def cat
|
30
|
-
22 end
|
31
|
-
```
|
32
|
-
|
33
|
-
Env options:
|
34
|
-
|
35
|
-
SYNTAX_SEARCH_RECORD_DIR=<dir>
|
36
|
-
|
37
|
-
When enabled, records the steps used to search for a syntax error to the given directory
|
38
|
-
|
39
|
-
Options:
|
40
|
-
EOM
|
41
|
-
|
42
|
-
opts.on("--help", "Help - displays this message") do |v|
|
43
|
-
puts opts
|
44
|
-
exit
|
45
|
-
end
|
46
|
-
|
47
|
-
opts.on("--record <dir>", "When enabled, records the steps used to search for a syntax error to the given directory") do |v|
|
48
|
-
options[:record_dir] = v
|
49
|
-
end
|
50
|
-
|
51
|
-
opts.on("--no-terminal", "Disable terminal highlighting") do |v|
|
52
|
-
options[:terminal] = false
|
53
|
-
end
|
54
|
-
end
|
55
|
-
parser.parse!
|
56
|
-
|
57
|
-
file = ARGV[0]
|
58
|
-
|
59
|
-
if file.nil? || file.empty?
|
60
|
-
# Display help if raw command
|
61
|
-
parser.parse! %w[--help]
|
62
|
-
end
|
63
|
-
|
64
|
-
file = Pathname(file)
|
65
|
-
options[:record_dir] = "tmp" if ENV["DEBUG"]
|
66
|
-
|
67
|
-
$stderr.puts "Record dir: #{options[:record_dir]}" if options[:record_dir]
|
68
|
-
|
69
|
-
SyntaxErrorSearch.call(
|
70
|
-
source: file.read,
|
71
|
-
filename: file.expand_path,
|
72
|
-
terminal: options[:terminal],
|
73
|
-
record_dir: options[:record_dir]
|
74
|
-
)
|
8
|
+
exit 1
|
data/lib/syntax_search/auto.rb
CHANGED
@@ -1,51 +1,7 @@
|
|
1
|
-
|
1
|
+
warn "syntax_search gem is deprecated please use `dead_end` instead"
|
2
|
+
warn
|
3
|
+
warn " $ gem install dead_end`"
|
4
|
+
warn
|
2
5
|
|
3
|
-
|
4
|
-
# method
|
5
|
-
module Kernel
|
6
|
-
alias_method :original_require, :require
|
7
|
-
alias_method :original_require_relative, :require_relative
|
8
|
-
alias_method :original_load, :load
|
9
|
-
|
10
|
-
def load(file, wrap = false)
|
11
|
-
original_load(file)
|
12
|
-
rescue SyntaxError => e
|
13
|
-
SyntaxErrorSearch.handle_error(e)
|
14
|
-
end
|
15
|
-
|
16
|
-
def require(file)
|
17
|
-
original_require(file)
|
18
|
-
rescue SyntaxError => e
|
19
|
-
SyntaxErrorSearch.handle_error(e)
|
20
|
-
end
|
21
|
-
|
22
|
-
def require_relative(file)
|
23
|
-
if Pathname.new(file).absolute?
|
24
|
-
original_require file
|
25
|
-
else
|
26
|
-
original_require File.expand_path("../#{file}", caller_locations(1, 1)[0].absolute_path)
|
27
|
-
end
|
28
|
-
rescue SyntaxError => e
|
29
|
-
SyntaxErrorSearch.handle_error(e)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# I honestly have no idea why this Object delegation is needed
|
34
|
-
# I keep staring at bootsnap and it doesn't have to do this
|
35
|
-
# is there a bug in their implementation they haven't caught or
|
36
|
-
# am I doing something different?
|
37
|
-
class Object
|
38
|
-
private
|
39
|
-
def load(path, wrap = false)
|
40
|
-
Kernel.load(path, wrap)
|
41
|
-
rescue SyntaxError => e
|
42
|
-
SyntaxErrorSearch.handle_error(e)
|
43
|
-
end
|
44
|
-
|
45
|
-
def require(path)
|
46
|
-
Kernel.require(path)
|
47
|
-
rescue SyntaxError => e
|
48
|
-
SyntaxErrorSearch.handle_error(e)
|
49
|
-
end
|
50
|
-
end
|
6
|
+
require "dead_end"
|
51
7
|
|
data/syntax_search.gemspec
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'lib/syntax_search/version'
|
4
|
-
|
5
3
|
Gem::Specification.new do |spec|
|
6
4
|
spec.name = "syntax_search"
|
7
|
-
spec.version =
|
5
|
+
spec.version = "0.2.1"
|
8
6
|
spec.authors = ["schneems"]
|
9
7
|
spec.email = ["richard.schneeman+foo@gmail.com"]
|
10
8
|
|
@@ -25,4 +23,6 @@ Gem::Specification.new do |spec|
|
|
25
23
|
spec.bindir = "exe"
|
26
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
25
|
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_dependency "dead_end", "> 0"
|
28
28
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- schneems
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
12
|
-
dependencies:
|
11
|
+
date: 2020-12-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dead_end
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: When you get an "unexpected end" in your syntax this gem helps you find
|
14
28
|
it
|
15
29
|
email:
|
@@ -35,23 +49,7 @@ files:
|
|
35
49
|
- bin/console
|
36
50
|
- bin/setup
|
37
51
|
- exe/syntax_search
|
38
|
-
- lib/syntax_search.rb
|
39
|
-
- lib/syntax_search/around_block_scan.rb
|
40
52
|
- lib/syntax_search/auto.rb
|
41
|
-
- lib/syntax_search/block_expand.rb
|
42
|
-
- lib/syntax_search/capture_code_context.rb
|
43
|
-
- lib/syntax_search/code_block.rb
|
44
|
-
- lib/syntax_search/code_frontier.rb
|
45
|
-
- lib/syntax_search/code_line.rb
|
46
|
-
- lib/syntax_search/code_search.rb
|
47
|
-
- lib/syntax_search/display_code_with_line_numbers.rb
|
48
|
-
- lib/syntax_search/display_invalid_blocks.rb
|
49
|
-
- lib/syntax_search/fyi.rb
|
50
|
-
- lib/syntax_search/heredoc_block_parse.rb
|
51
|
-
- lib/syntax_search/lex_all.rb
|
52
|
-
- lib/syntax_search/parse_blocks_from_indent_line.rb
|
53
|
-
- lib/syntax_search/version.rb
|
54
|
-
- lib/syntax_search/who_dis_syntax_error.rb
|
55
53
|
- syntax_search.gemspec
|
56
54
|
homepage: https://github.com/zombocom/syntax_search.git
|
57
55
|
licenses:
|
data/lib/syntax_search.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "syntax_search/version"
|
4
|
-
|
5
|
-
require 'tmpdir'
|
6
|
-
require 'stringio'
|
7
|
-
require 'pathname'
|
8
|
-
require 'ripper'
|
9
|
-
|
10
|
-
module SyntaxErrorSearch
|
11
|
-
class Error < StandardError; end
|
12
|
-
SEARCH_SOURCE_ON_ERROR_DEFAULT = true
|
13
|
-
|
14
|
-
def self.handle_error(e, search_source_on_error: SEARCH_SOURCE_ON_ERROR_DEFAULT)
|
15
|
-
raise e if !e.message.include?("end-of-input")
|
16
|
-
|
17
|
-
filename = e.message.split(":").first
|
18
|
-
|
19
|
-
$stderr.sync = true
|
20
|
-
$stderr.puts "Run `$ syntax_search #{filename}` for more options\n"
|
21
|
-
|
22
|
-
if search_source_on_error
|
23
|
-
self.call(
|
24
|
-
source: Pathname(filename).read,
|
25
|
-
filename: filename,
|
26
|
-
terminal: true,
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
30
|
-
$stderr.puts ""
|
31
|
-
$stderr.puts ""
|
32
|
-
raise e
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.call(source: , filename: , terminal: false, record_dir: nil)
|
36
|
-
search = CodeSearch.new(source, record_dir: record_dir).call
|
37
|
-
|
38
|
-
blocks = search.invalid_blocks
|
39
|
-
DisplayInvalidBlocks.new(
|
40
|
-
blocks: blocks,
|
41
|
-
filename: filename,
|
42
|
-
terminal: terminal,
|
43
|
-
code_lines: search.code_lines,
|
44
|
-
invalid_type: invalid_type(source),
|
45
|
-
io: $stderr
|
46
|
-
).call
|
47
|
-
end
|
48
|
-
|
49
|
-
# Used for counting spaces
|
50
|
-
module SpaceCount
|
51
|
-
def self.indent(string)
|
52
|
-
string.split(/\S/).first&.length || 0
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# This will tell you if the `code_lines` would be valid
|
57
|
-
# if you removed the `without_lines`. In short it's a
|
58
|
-
# way to detect if we've found the lines with syntax errors
|
59
|
-
# in our document yet.
|
60
|
-
#
|
61
|
-
# code_lines = [
|
62
|
-
# CodeLine.new(line: "def foo\n", index: 0)
|
63
|
-
# CodeLine.new(line: " def bar\n", index: 1)
|
64
|
-
# CodeLine.new(line: "end\n", index: 2)
|
65
|
-
# ]
|
66
|
-
#
|
67
|
-
# SyntaxErrorSearch.valid_without?(
|
68
|
-
# without_lines: code_lines[1],
|
69
|
-
# code_lines: code_lines
|
70
|
-
# ) # => true
|
71
|
-
#
|
72
|
-
# SyntaxErrorSearch.valid?(code_lines) # => false
|
73
|
-
def self.valid_without?(without_lines: , code_lines:)
|
74
|
-
lines = code_lines - Array(without_lines).flatten
|
75
|
-
|
76
|
-
if lines.empty?
|
77
|
-
return true
|
78
|
-
else
|
79
|
-
return valid?(lines)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.invalid?(source)
|
84
|
-
source = source.join if source.is_a?(Array)
|
85
|
-
source = source.to_s
|
86
|
-
|
87
|
-
Ripper.new(source).tap(&:parse).error?
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns truthy if a given input source is valid syntax
|
91
|
-
#
|
92
|
-
# SyntaxErrorSearch.valid?(<<~EOM) # => true
|
93
|
-
# def foo
|
94
|
-
# end
|
95
|
-
# EOM
|
96
|
-
#
|
97
|
-
# SyntaxErrorSearch.valid?(<<~EOM) # => false
|
98
|
-
# def foo
|
99
|
-
# def bar # Syntax error here
|
100
|
-
# end
|
101
|
-
# EOM
|
102
|
-
#
|
103
|
-
# You can also pass in an array of lines and they'll be
|
104
|
-
# joined before evaluating
|
105
|
-
#
|
106
|
-
# SyntaxErrorSearch.valid?(
|
107
|
-
# [
|
108
|
-
# "def foo\n",
|
109
|
-
# "end\n"
|
110
|
-
# ]
|
111
|
-
# ) # => true
|
112
|
-
#
|
113
|
-
# SyntaxErrorSearch.valid?(
|
114
|
-
# [
|
115
|
-
# "def foo\n",
|
116
|
-
# " def bar\n", # Syntax error here
|
117
|
-
# "end\n"
|
118
|
-
# ]
|
119
|
-
# ) # => false
|
120
|
-
#
|
121
|
-
# As an FYI the CodeLine class instances respond to `to_s`
|
122
|
-
# so passing a CodeLine in as an object or as an array
|
123
|
-
# will convert it to it's code representation.
|
124
|
-
def self.valid?(source)
|
125
|
-
!invalid?(source)
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
def self.invalid_type(source)
|
130
|
-
WhoDisSyntaxError.new(source).call.error_symbol
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
require_relative "syntax_search/code_line"
|
135
|
-
require_relative "syntax_search/code_block"
|
136
|
-
require_relative "syntax_search/code_frontier"
|
137
|
-
require_relative "syntax_search/display_invalid_blocks"
|
138
|
-
require_relative "syntax_search/around_block_scan"
|
139
|
-
require_relative "syntax_search/block_expand"
|
140
|
-
require_relative "syntax_search/parse_blocks_from_indent_line"
|
141
|
-
|
142
|
-
require_relative "syntax_search/code_search"
|
143
|
-
require_relative "syntax_search/who_dis_syntax_error"
|
144
|
-
require_relative "syntax_search/heredoc_block_parse"
|
145
|
-
require_relative "syntax_search/lex_all"
|
@@ -1,193 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
#
|
3
|
-
module SyntaxErrorSearch
|
4
|
-
# This class is useful for exploring contents before and after
|
5
|
-
# a block
|
6
|
-
#
|
7
|
-
# It searches above and below the passed in block to match for
|
8
|
-
# whatever criteria you give it:
|
9
|
-
#
|
10
|
-
# Example:
|
11
|
-
#
|
12
|
-
# def dog
|
13
|
-
# puts "bark"
|
14
|
-
# puts "bark"
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# scan = AroundBlockScan.new(
|
18
|
-
# code_lines: code_lines
|
19
|
-
# block: CodeBlock.new(lines: code_lines[1])
|
20
|
-
# )
|
21
|
-
#
|
22
|
-
# scan.scan_while { true }
|
23
|
-
#
|
24
|
-
# puts scan.before_index # => 0
|
25
|
-
# puts scan.after_index # => 3
|
26
|
-
#
|
27
|
-
# Contents can also be filtered using AroundBlockScan#skip
|
28
|
-
#
|
29
|
-
# To grab the next surrounding indentation use AroundBlockScan#scan_adjacent_indent
|
30
|
-
class AroundBlockScan
|
31
|
-
def initialize(code_lines: , block:)
|
32
|
-
@code_lines = code_lines
|
33
|
-
@orig_before_index = block.lines.first.index
|
34
|
-
@orig_after_index = block.lines.last.index
|
35
|
-
@orig_indent = block.current_indent
|
36
|
-
@skip_array = []
|
37
|
-
@after_array = []
|
38
|
-
@before_array = []
|
39
|
-
@stop_after_kw = false
|
40
|
-
end
|
41
|
-
|
42
|
-
def skip(name)
|
43
|
-
@skip_array << name
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
def stop_after_kw
|
48
|
-
@stop_after_kw = true
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def scan_while(&block)
|
53
|
-
stop_next = false
|
54
|
-
|
55
|
-
kw_count = 0
|
56
|
-
end_count = 0
|
57
|
-
@before_index = before_lines.reverse_each.take_while do |line|
|
58
|
-
next false if stop_next
|
59
|
-
next true if @skip_array.detect {|meth| line.send(meth) }
|
60
|
-
|
61
|
-
kw_count += 1 if line.is_kw?
|
62
|
-
end_count += 1 if line.is_end?
|
63
|
-
if @stop_after_kw && kw_count > end_count
|
64
|
-
stop_next = true
|
65
|
-
end
|
66
|
-
|
67
|
-
block.call(line)
|
68
|
-
end.reverse.first&.index
|
69
|
-
|
70
|
-
stop_next = false
|
71
|
-
kw_count = 0
|
72
|
-
end_count = 0
|
73
|
-
@after_index = after_lines.take_while do |line|
|
74
|
-
next false if stop_next
|
75
|
-
next true if @skip_array.detect {|meth| line.send(meth) }
|
76
|
-
|
77
|
-
kw_count += 1 if line.is_kw?
|
78
|
-
end_count += 1 if line.is_end?
|
79
|
-
if @stop_after_kw && end_count > kw_count
|
80
|
-
stop_next = true
|
81
|
-
end
|
82
|
-
|
83
|
-
block.call(line)
|
84
|
-
end.last&.index
|
85
|
-
self
|
86
|
-
end
|
87
|
-
|
88
|
-
def capture_neighbor_context
|
89
|
-
lines = []
|
90
|
-
kw_count = 0
|
91
|
-
end_count = 0
|
92
|
-
before_lines.reverse.each do |line|
|
93
|
-
next if line.empty?
|
94
|
-
break if line.indent < @orig_indent
|
95
|
-
next if line.indent != @orig_indent
|
96
|
-
|
97
|
-
kw_count += 1 if line.is_kw?
|
98
|
-
end_count += 1 if line.is_end?
|
99
|
-
if kw_count != 0 && kw_count == end_count
|
100
|
-
lines << line
|
101
|
-
break
|
102
|
-
end
|
103
|
-
|
104
|
-
lines << line
|
105
|
-
end
|
106
|
-
|
107
|
-
lines.reverse!
|
108
|
-
|
109
|
-
kw_count = 0
|
110
|
-
end_count = 0
|
111
|
-
after_lines.each do |line|
|
112
|
-
# puts "line: #{line.number} #{line.original_line}, indent: #{line.indent}, #{line.empty?} #{line.indent == @orig_indent}"
|
113
|
-
|
114
|
-
next if line.empty?
|
115
|
-
break if line.indent < @orig_indent
|
116
|
-
next if line.indent != @orig_indent
|
117
|
-
|
118
|
-
kw_count += 1 if line.is_kw?
|
119
|
-
end_count += 1 if line.is_end?
|
120
|
-
if kw_count != 0 && kw_count == end_count
|
121
|
-
lines << line
|
122
|
-
break
|
123
|
-
end
|
124
|
-
|
125
|
-
lines << line
|
126
|
-
end
|
127
|
-
lines.select! {|line| !line.is_comment? }
|
128
|
-
|
129
|
-
lines
|
130
|
-
end
|
131
|
-
|
132
|
-
def on_falling_indent
|
133
|
-
last_indent = @orig_indent
|
134
|
-
before_lines.reverse.each do |line|
|
135
|
-
next if line.empty?
|
136
|
-
if line.indent < last_indent
|
137
|
-
yield line
|
138
|
-
last_indent = line.indent
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
last_indent = @orig_indent
|
143
|
-
after_lines.each do |line|
|
144
|
-
next if line.empty?
|
145
|
-
if line.indent < last_indent
|
146
|
-
yield line
|
147
|
-
last_indent = line.indent
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def scan_neighbors
|
153
|
-
self.scan_while {|line| line.not_empty? && line.indent >= @orig_indent }
|
154
|
-
end
|
155
|
-
|
156
|
-
def scan_adjacent_indent
|
157
|
-
before_indent = @code_lines[@orig_before_index.pred]&.indent || 0
|
158
|
-
after_indent = @code_lines[@orig_after_index.next]&.indent || 0
|
159
|
-
|
160
|
-
indent = [before_indent, after_indent].min
|
161
|
-
self.scan_while {|line| line.not_empty? && line.indent >= indent }
|
162
|
-
|
163
|
-
self
|
164
|
-
end
|
165
|
-
|
166
|
-
def start_at_next_line
|
167
|
-
before_index; after_index
|
168
|
-
@before_index -= 1
|
169
|
-
@after_index += 1
|
170
|
-
self
|
171
|
-
end
|
172
|
-
|
173
|
-
def code_block
|
174
|
-
CodeBlock.new(lines: @code_lines[before_index..after_index])
|
175
|
-
end
|
176
|
-
|
177
|
-
def before_index
|
178
|
-
@before_index ||= @orig_before_index
|
179
|
-
end
|
180
|
-
|
181
|
-
def after_index
|
182
|
-
@after_index ||= @orig_after_index
|
183
|
-
end
|
184
|
-
|
185
|
-
private def before_lines
|
186
|
-
@code_lines[0...@orig_before_index]
|
187
|
-
end
|
188
|
-
|
189
|
-
private def after_lines
|
190
|
-
@code_lines[@orig_after_index.next..-1]
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|