1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
module Rugments
module Lexers
class VimL < RegexLexer
title 'VimL'
desc 'VimL, the scripting language for the Vim editor (vim.org)'
tag 'viml'
aliases 'vim', 'vimscript', 'ex'
filenames '*.vim', '*.vba', '.vimrc', '.exrc', '.gvimrc',
'_vimrc', '_exrc', '_gvimrc' # _ names for windows
mimetypes 'text/x-vim'
def self.keywords
load Pathname.new(__FILE__).dirname.join('viml/keywords.rb')
keywords
end
state :root do
rule /^(\s*)(".*?)$/ do
groups Text, Comment
end
rule /^\s*\\/, Str::Escape
rule /[ \t]+/, Text
# TODO: regexes can have other delimiters
rule %r{/(\\\\|\\/|[^\n/])*/}, Str::Regex
rule %r{"(\\\\|\\"|[^\n"])*"}, Str::Double
rule %r{'(\\\\|\\'|[^\n'])*'}, Str::Single
# if it's not a string, it's a comment.
rule /(?<=\s)"[^-:.%#=*].*?$/, Comment
rule /-?\d+/, Num
rule /#[0-9a-f]{6}/i, Num::Hex
rule /^:/, Punctuation
rule /[():<>+=!\[\]{}\|,~.-]/, Punctuation
rule /\b(let|if|else|endif|elseif|fun|function|endfunction)\b/,
Keyword
rule /\b(NONE|bold|italic|underline|dark|light)\b/, Name::Builtin
rule /[absg]:\w+\b/, Name::Variable
rule /\b\w+\b/ do |m|
name = m[0]
keywords = self.class.keywords
if mapping_contains?(keywords[:command], name)
token Keyword
elsif mapping_contains?(keywords[:option], name)
token Name::Builtin
elsif mapping_contains?(keywords[:auto], name)
token Name::Builtin
else
token Text
end
end
# no errors in VimL!
rule /./m, Text
end
def mapping_contains?(mapping, word)
shortest, longest = find_likely_mapping(mapping, word)
shortest and word.start_with?(shortest) and
longest and longest.start_with?(word)
end
# binary search through the mappings to find the one that's likely
# to actually work.
def find_likely_mapping(mapping, word)
min = 0
max = mapping.size
until max == min
mid = (max + min) / 2
cmp, _ = mapping[mid]
case word <=> cmp
when 1
# too low
min = mid + 1
when -1
# too high
max = mid
when 0
# just right, abort!
return mapping[mid]
end
end
mapping[max - 1]
end
end
end
end
|