Module: RuVim::Lang::Ruby
- Defined in:
- lib/ruvim/lang/ruby.rb
Constant Summary collapse
- PRISM_KEYWORD_TYPES =
%i[ KEYWORD_ALIAS KEYWORD_AND KEYWORD_BEGIN KEYWORD_BEGIN_UPCASE KEYWORD_BREAK KEYWORD_CASE KEYWORD_CLASS KEYWORD_DEF KEYWORD_DEFINED KEYWORD_DO KEYWORD_ELSE KEYWORD_ELSIF KEYWORD_END KEYWORD_ENSURE KEYWORD_FALSE KEYWORD_FOR KEYWORD_IF KEYWORD_IF_MODIFIER KEYWORD_IN KEYWORD_MODULE KEYWORD_NEXT KEYWORD_NIL KEYWORD_NOT KEYWORD_OR KEYWORD_REDO KEYWORD_RESCUE KEYWORD_RESCUE_MODIFIER KEYWORD_RETRY KEYWORD_RETURN KEYWORD_SELF KEYWORD_SUPER KEYWORD_THEN KEYWORD_TRUE KEYWORD_UNDEF KEYWORD_UNLESS KEYWORD_UNLESS_MODIFIER KEYWORD_UNTIL KEYWORD_UNTIL_MODIFIER KEYWORD_WHEN KEYWORD_WHILE KEYWORD_WHILE_MODIFIER KEYWORD_YIELD MISSING ].freeze
- PRISM_STRING_TYPES =
%i[ STRING_BEGIN STRING_CONTENT STRING_END SYMBOL_BEGIN REGEXP_BEGIN REGEXP_CONTENT REGEXP_END XSTRING_BEGIN XSTRING_CONTENT XSTRING_END WORDS_BEGIN QWORDS_BEGIN WORDS_SEPARATOR STRING CHARACTER_LITERAL ].freeze
- PRISM_NUMBER_TYPES =
%i[ INTEGER FLOAT RATIONAL_NUMBER IMAGINARY_NUMBER UINTEGER ].freeze
- PRISM_COMMENT_TYPES =
%i[ COMMENT EMBDOC_BEGIN EMBDOC_LINE EMBDOC_END ].freeze
- PRISM_VARIABLE_TYPES =
%i[ INSTANCE_VARIABLE CLASS_VARIABLE GLOBAL_VARIABLE ].freeze
- PRISM_CONSTANT_TYPES =
%i[ CONSTANT ].freeze
- INDENT_OPEN_RE =
Keywords that open a new indentation level
/\A\s*(?:def|class|module|if|unless|while|until|for|begin|case)\b/- INDENT_DO_RE =
doat end of line (block form) /\bdo\s*(\|[^|]*\|)?\s*$/- INDENT_BRACKET_OPEN_RE =
Opening brackets at end of line
/[\[({]\s*$/- INDENT_CLOSE_RE =
Keywords that close an indentation level
/\A\s*(?:end|[}\])])/- INDENT_MID_RE =
Keywords at same level as their opening keyword (dedent for the line itself)
/\A\s*(?:else|elsif|when|rescue|ensure|in)\b/- MODIFIER_RE =
Modifier keywords that do NOT open indentation
/\b(?:if|unless|while|until|rescue)\b/- DEDENT_TRIGGERS =
Dedent trigger patterns keyed by the last character typed
{ "d" => /\A(\s*)end\z/, "e" => /\A(\s*)(?:else|rescue|ensure)\z/, "f" => /\A(\s*)elsif\z/, "n" => /\A(\s*)(?:when|in)\z/ }.freeze
Class Method Summary collapse
- .calculate_indent(lines, target_row, shiftwidth) ⇒ Object
- .color_columns(text) ⇒ Object
-
.dedent_trigger(char) ⇒ Object
Returns the dedent pattern for the given character, or nil.
-
.indent_trigger?(line) ⇒ Boolean
Returns true if the line should increase indent for the next line.
- .on_save(ctx, path) ⇒ Object
Class Method Details
.calculate_indent(lines, target_row, shiftwidth) ⇒ Object
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 |
# File 'lib/ruvim/lang/ruby.rb', line 113 def calculate_indent(lines, target_row, shiftwidth) depth = 0 (0...target_row).each do |row| line = lines[row] stripped = line.to_s.lstrip # Skip blank and comment lines for indent computation next if stripped.empty? || stripped.start_with?("#") # Check if the line opens a new level if stripped.match?(INDENT_OPEN_RE) # Check for modifier form: something before the keyword on the same line # e.g. "return if true" — if keyword is not at start, it's a modifier first_word = stripped[/\A(\w+)/, 1] if %w[if unless while until rescue].include?(first_word) depth += 1 elsif %w[def class module begin case for].include?(first_word) depth += 1 end elsif stripped.match?(INDENT_DO_RE) depth += 1 end # Count opening brackets (not at end-of-line pattern, but individual) stripped.each_char do |ch| case ch when "{", "[", "(" depth += 1 when "}", "]", ")" depth -= 1 end end if !stripped.match?(INDENT_OPEN_RE) && !stripped.match?(INDENT_DO_RE) # Handle closing keywords if stripped.match?(/\A\s*end\b/) depth -= 1 end # Handle mid keywords (else/elsif/when/rescue/ensure) — they don't change depth for following lines end # Now compute indent for target_row target_line = lines[target_row].to_s.lstrip # If target line is a closing keyword, dedent if target_line.match?(INDENT_CLOSE_RE) depth -= 1 elsif target_line.match?(INDENT_MID_RE) depth -= 1 end depth = 0 if depth < 0 depth * shiftwidth end |
.color_columns(text) ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/ruvim/lang/ruby.rb', line 213 def color_columns(text) cols = {} Prism.lex(text).value.each do |entry| token = entry[0] type = token.type range = token.location.start_offset...token.location.end_offset if PRISM_STRING_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::STRING_COLOR unless cols.key?(idx) } elsif PRISM_KEYWORD_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::KEYWORD_COLOR unless cols.key?(idx) } elsif PRISM_NUMBER_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::NUMBER_COLOR unless cols.key?(idx) } elsif PRISM_VARIABLE_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::VARIABLE_COLOR unless cols.key?(idx) } elsif PRISM_CONSTANT_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::CONSTANT_COLOR unless cols.key?(idx) } elsif PRISM_COMMENT_TYPES.include?(type) range.each { |idx| cols[idx] = Highlighter::COMMENT_COLOR } end end cols end |
.dedent_trigger(char) ⇒ Object
Returns the dedent pattern for the given character, or nil
186 187 188 |
# File 'lib/ruvim/lang/ruby.rb', line 186 def dedent_trigger(char) DEDENT_TRIGGERS[char] end |
.indent_trigger?(line) ⇒ Boolean
Returns true if the line should increase indent for the next line
169 170 171 172 173 174 175 |
# File 'lib/ruvim/lang/ruby.rb', line 169 def indent_trigger?(line) stripped = line.to_s.rstrip.lstrip first_word = stripped[/\A(\w+)/, 1].to_s return true if %w[def class module if unless while until for begin case].include?(first_word) return true if stripped.match?(/\bdo\s*(\|[^|]*\|)?\s*$/) false end |
.on_save(ctx, path) ⇒ Object
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/ruvim/lang/ruby.rb', line 190 def on_save(ctx, path) return unless path && File.exist?(path) return if ctx.editor.respond_to?(:restricted_mode?) && ctx.editor.restricted_mode? output, status = Open3.capture2e("ruby", "-wc", path) = output.sub(/^Syntax OK\n?\z/m, "").strip if !status.success? || !.empty? buffer_id = ctx.buffer.id items = .lines.filter_map { |line| if line =~ /\A.+?:(\d+):/ { buffer_id: buffer_id, row: $1.to_i - 1, col: 0, text: line.strip } end } items = [{ buffer_id: buffer_id, row: 0, col: 0, text: }] if items.empty? ctx.editor.set_quickfix_list(items) first = .lines.first.to_s.strip hint = items.size > 1 ? " (Q to see all, #{items.size} total)" : "" ctx.editor.echo_error("#{first}#{hint}") else ctx.editor.set_quickfix_list([]) end end |