diff --git a/assets/highlighting-tests/ruby.rb b/assets/highlighting-tests/ruby.rb new file mode 100644 index 00000000000..69b1c682316 --- /dev/null +++ b/assets/highlighting-tests/ruby.rb @@ -0,0 +1,102 @@ +# Comments +# Single-line comment + +=begin +Multi-line +comment +=end + +# Numbers +42 +3.14 +0.5 +1e10 +1.5e-3 +0xff +0xFF +0b1010 +0o77 +1_000_000 +3.14r +2i + +# Constants +true +false +nil +Object +String + +# Strings +'single quotes with escape: \' \n \t \\' +"double quotes with escape: \" \n \t \\" +`echo shell command` + +# Symbols and variables +:symbol +:method_name? +@instance_var +@@class_var +$global_var + +# Control flow keywords +if true + puts "yes" +elsif false + puts "no" +else + puts "maybe" +end + +unless nil + puts "not nil" +end + +case 42 +when 1 + puts "one" +else + puts "other" +end + +for i in 1..3 + next if i == 2 + break if i == 3 +end + +while false + redo +end + +begin + raise "oops" +rescue StandardError => e + retry +ensure + puts e +end + +# Definitions and method calls +module Demo + class Animal + def initialize(name) + @name = name + end + + def speak! = puts "#{@name} speaks" + end +end + +alias old_speak speak! +undef old_speak + +BEGIN { puts "start" } +END { puts "finish" } +defined? Demo +self +super +yield + +puts "hello" +Array.new(3) +greet("world") diff --git a/crates/lsh/definitions/ruby.lsh b/crates/lsh/definitions/ruby.lsh new file mode 100644 index 00000000000..0e7079cd12d --- /dev/null +++ b/crates/lsh/definitions/ruby.lsh @@ -0,0 +1,100 @@ +#[display_name = "Ruby"] +#[path = "**/*.rb"] +#[path = "**/*.rake"] +#[path = "**/*.ru"] +#[path = "**/Gemfile"] +#[path = "**/Rakefile"] +pub fn ruby() { + var zero = 0; + until /$/ { + yield other; + + if off == zero { + if /=begin\>/ { + loop { + yield comment; + await input; + if off == zero { + if /=end\>/ { + yield comment; + break; + } + } + } + continue; + } + } + + if /#.*/ { + yield comment; + } else if /'/ { + until /$/ { + yield string; + if /\\./ {} + else if /'/ { yield string; break; } + await input; + } + } else if /"/ { + until /$/ { + yield string; + if /\\./ {} + else if /"/ { yield string; break; } + await input; + } + } else if /`/ { + loop { + yield string; + if /\\./ {} + else if /`/ { yield string; break; } + await input; + } + } else if /(?:begin|break|case|class|do|else|elsif|end|ensure|for|if|in|module|next|redo|rescue|retry|return|then|unless|until|when|while)\>/ { + yield keyword.control; + } else if /def\s+(\w+[!?=]?)/ { + yield keyword.control; + yield $1 as method; + } else if /(?:BEGIN|END|alias|defined\?|self|super|undef|yield)\>/ { + yield keyword.other; + } else if /(?:true|false|nil)\>/ { + yield constant.language; + } else if /\.\.\.?/ { + // Range operator. + } else if /(?i:-?(?:0x[\da-fA-F_]+|0b[01_]+|0o[0-7_]+)r?i?)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + } else if /(?i:-?[\d_]+\.[\d_]+(?:e[+-]?[\d_]+)?r?i?)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + } else if /(?i:-?\.[\d_]+(?:e[+-]?[\d_]+)?r?i?)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + } else if /(?i:-?[\d_]+(?:e[+-]?[\d_]+)?r?i?)/ { + if /\w+/ { + // Invalid numeric literal + } else { + yield constant.numeric; + } + } else if /(?:@{1,2}|\$)[A-Za-z_]\w*/ { + yield variable; + } else if /:[A-Za-z_]\w*[!?=]?/ { + yield constant.language; + } else if /[A-Z]\w*/ { + yield constant.language; + } else if /(\w+[!?=]?)\s*\(/ { + yield $1 as method; + } else if /\w+[!?=]?/ { + // Gobble word chars to align the next iteration on a word boundary. + } + + yield other; + } +}