class SyntaxSuggest::CodeLine
表示给定源文件的单行代码
此对象包含有关该行的元数据,例如缩进量、是否为空以及词法数据,例如是否包含“end”或关键字。
可以关闭行的可见性。将行标记为不可见表示它不应用于语法检查。它在功能上与注释掉它相同。
示例
line = CodeLine.from_source("def foo\n").first line.number => 1 line.empty? # => false line.visible? # => true line.mark_invisible line.visible? # => false
常量
- TRAILING_SLASH
属性
当代码行被标记为不可见时,我们会保留其原始行值,这对于调试和显示额外的上下文很有用。
DisplayCodeWithLineNumbers
将呈现提供给它的所有行,而不仅仅是可见的行,它使用 original 方法来获取它们。
公共类方法
来源
# File lib/syntax_suggest/code_line.rb, line 29 def self.from_source(source, lines: nil) lines ||= source.lines lex_array_for_line = LexAll.new(source: source, source_lines: lines).each_with_object(Hash.new { |h, k| h[k] = [] }) { |lex, hash| hash[lex.line] << lex } lines.map.with_index do |line, index| CodeLine.new( line: line, index: index, lex: lex_array_for_line[index + 1] ) end end
从源字符串返回一个 CodeLine
对象数组
来源
# File lib/syntax_suggest/code_line.rb, line 42 def initialize(line:, index:, lex:) @lex = lex @line = line @index = index @original = line @line_number = @index + 1 strip_line = line.dup strip_line.lstrip! @indent = if (@empty = strip_line.empty?) line.length - 1 # Newline removed from strip_line is not "whitespace" else line.length - strip_line.length end set_kw_end end
公共实例方法
来源
# File lib/syntax_suggest/code_line.rb, line 150 def <=>(other) index <=> other.index end
比较运算符,用于相等性和排序
来源
# File lib/syntax_suggest/code_line.rb, line 115 def empty? @empty end
一个“empty?”行是最初在源代码中留空的行,而“隐藏”行是我们后来标记为“不可见”的行
来源
# File lib/syntax_suggest/code_line.rb, line 172 def ignore_newline_not_beg? @ignore_newline_not_beg end
- 不稳定的 API
-
具有“on_ignored_nl”类型标记且不是“BEG”类型的行似乎是将多行连接成一行的良好代理。
此谓词方法用于确定何时满足这两个条件。
已知此方法无法处理的一个情况是
Ripper.lex <<~EOM a && b || c EOM
由于某种原因,这引入了 “on_ignore_newline”,但类型为 BEG
来源
# File lib/syntax_suggest/code_line.rb, line 72 def indent_index @indent_index ||= [indent, index] end
用于通过缩进级别进行稳定排序
Ruby 的排序不是“稳定”的,这意味着当多个元素具有相同的值时,不能保证它们会按照放入的顺序返回。
因此,当多行代码具有相同的缩进级别时,它们会按其索引值排序,该索引值是唯一且一致的。
这主要是为了测试套件的一致性
来源
# File lib/syntax_suggest/code_line.rb, line 87 def is_end? @is_end end
如果代码行被确定为包含“end”关键字,则返回 true
来源
# File lib/syntax_suggest/code_line.rb, line 81 def is_kw? @is_kw end
如果代码行被确定为包含与“end”匹配的关键字,则返回 true
例如:“def”、“do”、“begin”、“ensure” 等。
来源
# File lib/syntax_suggest/code_line.rb, line 96 def mark_invisible @line = "" end
用于隐藏行
搜索算法会将行分组到块中,然后如果确定这些块表示有效的代码,则会将其隐藏
来源
# File lib/syntax_suggest/code_line.rb, line 120 def not_empty? !empty? end
与 “empty?” 相反(注意:与 “visible?” 不同)
来源
# File lib/syntax_suggest/code_line.rb, line 133 def to_s line end
渲染给定行
还允许我们将源代码表示为代码行数组。
当我们有一个代码行元素数组时,在数组上调用“join”将调用每个元素上的“to_s”,这本质上会将其转换回其原始源代码字符串。
来源
# File lib/syntax_suggest/code_line.rb, line 184 def trailing_slash? last = @lex.last last&.type == :on_tstring_end end
来源
# File lib/syntax_suggest/code_line.rb, line 103 def visible? !line.empty? end
表示该行被标记为“不可见”。令人困惑的是,“空”行是可见的……它们除了换行符 (“n”) 之外不包含任何源代码。
私有实例方法
来源
# File lib/syntax_suggest/code_line.rb, line 206 def set_kw_end oneliner_count = 0 in_oneliner_def = nil kw_count = 0 end_count = 0 @ignore_newline_not_beg = false @lex.each do |lex| kw_count += 1 if lex.is_kw? end_count += 1 if lex.is_end? if lex.type == :on_ignored_nl @ignore_newline_not_beg = !lex.expr_beg? end if in_oneliner_def.nil? in_oneliner_def = :ENDFN if lex.state.allbits?(Ripper::EXPR_ENDFN) elsif lex.state.allbits?(Ripper::EXPR_ENDFN) # Continue elsif lex.state.allbits?(Ripper::EXPR_BEG) in_oneliner_def = :BODY if lex.token == "=" elsif lex.state.allbits?(Ripper::EXPR_END) # We found an endless method, count it oneliner_count += 1 if in_oneliner_def == :BODY in_oneliner_def = nil else in_oneliner_def = nil end end kw_count -= oneliner_count @is_kw = (kw_count - end_count) > 0 @is_end = (end_count - kw_count) > 0 end
无尽方法检测
来自 github.com/ruby/irb/commit/826ae909c9c93a2ddca6f9cfcd9c94dbf53d44ab 检测 “oneliner” 似乎需要一个状态机。这可以通过主要查看 “state”(最后一个值)来完成
ENDFN -> BEG (token = '=' ) -> END