#!/usr/bin/env ruby -w # encoding: UTF-8 # # = VimSyntax.rb -- The TaskJuggler III Project Management Software # # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011 # by Chris Schlaeger # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # require 'taskjuggler/SyntaxReference' class TaskJuggler # This class is a generator for vim (http://www.vim.org) TaskJuggler syntax # highlighting files. class VimSyntax # Create a generator object. def initialize @reference = SyntaxReference.new @properties = [] @attributes = [] @optionBlocks = [] @reference.keywords.each_value do |kw| if kw.isProperty? @properties << kw else @attributes << kw end if !kw.optionalAttributes.empty? @optionBlocks << kw end end @file = nil end # Generate the vim syntax file into _file_. def generate(file) @file = File.open(file, 'w') header setLocal keywords matches regions highlights @file.close end private def header @file.write <<"EOT" " Vim syntax file " Language: TaskJuggler " Maintainer: TaskJuggler Developers " Last Change: #{Time.now} " This file was automatically generated by VimSyntax.rb if exists("b:current_syntax") finish endif EOT end def setLocal cinwords = [] @optionBlocks.each { |kw| cinwords += kw.names } cinwords.uniq!.sort! @file.write <<'EOT' setlocal softtabstop=2 setlocal cindent shiftwidth=2 setlocal tabstop=2 setlocal expandtab setlocal cinoptions=g0,t0,+0,(0,c0,C1 EOT @file.write "setlocal cinwords=#{cinwords.join(',')}\n" @file.write <<'EOT' setlocal cinkeys=0{,0},!^F,o,O setlocal cindent EOT end def regions @optionBlocks.each do |kw| single = kw.names.length == 1 kw.names.each do |name| normalizedName = "#{normalize(kw.keyword)}" + "#{single ? '' : "_#{name}"}" tag = name == 'supplement' ? kw.keyword.gsub(/\./, ' ') : name @file.write "syn region tjpblk_#{normalizedName}" + " start=/^\\s*#{tag}\\s.*{/ end=/^\\s*}/ transparent" # We allow properties and special attributes to be folded. foldable = %w( task.timesheet project ) @file.write " fold" if @properties.include?(kw) || foldable.include?(kw.keyword) # The header is part of the region. So we must make sure that common # parameters and the property/attribute name are contained as well. @file.write " contains=@tjpcommon,tjp_#{normalizedName}" kw.optionalAttributes.each do |oa| tag = normalize(oa.keyword) @file.write ",tjp_#{tag}" if !oa.optionalAttributes.empty? # Option blocks may be contained as block or non-block. @file.write ",tjpblk_#{tag}" end end if name == 'supplement' @file.write(',tjp_supplement') end if !kw.globalScope? # Every region but a property and 'project' is contained. @file.write " contained" end @file.puts end end @file.write <<'EOT' syn region tjpblk_macro start=/macro\s\+\h\w*\s*\[/ end=/\]$/ transparent fold contains=ALL syn region tjpstring start=/"/ skip=/\\"/ end=/"/ syn region tjpstring start=/'/ skip=/\\'/ end=/'/ syn region tjpstring start=/\s-8<-$/ end=/^\s*->8-/ syn region tjpmlcomment start=+/\*+ end=+\*/+ syn sync fromstart set foldmethod=syntax EOT end def keywords %w( macro project supplement ).each do |kw| @file.puts "syn keyword tjp_#{kw} #{kw} contained" end @file.puts # Property keywords @properties.each do |kw| single = kw.names.length == 1 kw.names.each do |name| # Ignore the 'supplement' entries. They are not real properties. next if name == 'supplement' @file.puts "syn keyword tjp_#{normalize(kw.keyword)}" + "#{single ? '' : "_#{name}"} #{name} contained" @file.puts "hi def link tjp_#{normalize(kw.keyword)}" + "#{single ? '' : "_#{name}"} Function" end end @file.puts # Attribute keywords @attributes.each do |kw| next if %w( resourcereport taskreport textreport ).include?(kw.keyword) single = kw.names.length == 1 kw.names.each do |name| break if [ '%', '(', '~', 'include', 'macro', 'project', 'supplement' ].include?(name) @file.puts "syn keyword tjp_#{normalize(kw.keyword)}" + "#{single ? '' : "_#{name}"} #{name}" + "#{kw.globalScope? && !@optionBlocks.include?(kw) ? '' : ' contained'}" @file.puts "hi def link tjp_#{normalize(kw.keyword)}" + "#{single ? '' : "_#{name}"} Type" end end @file.puts end def matches @file.write <<'EOT' syn match tjparg contained /\${.*}/ syn match tjpcomment /#.*$/ syn match tjpcomment "//.*$" syn match tjpinclude /include.*$/ syn match tjpnumber /\s[-+]\?\d\+\(\.\d\+\)\?\([hdwmy]\|min\)\?/ syn match tjpdate /\s\d\{4}-\d\{1,2}-\d\{1,2}\(-\d\{1,2}:\d\{1,2}\(:\d\{1,2}\)\?\(-[-+]\?\d\{4}\)\?\)\?/ syn match tjptime /\s\d\{1,2}:\d\d\(:\d\d\)\?/ syn cluster tjpcommon contains=tjpcomment,tjpdate,tjptime,tjpstring,tjpnumber EOT end def highlights @file.write <<'EOT' hi def link tjp_macro PreProc hi def link tjp_supplement Function hi def link tjp_project Function hi def link tjpproperty Function hi def link tjpattribute Type hi def link tjparg Special hi def link tjpstring String hi def link tjpcomment Comment hi def link tjpmlcomment Comment hi def link tjpinclude Include hi def link tjpdate Constant hi def link tjptime Constant hi def link tjpnumber Number let b:current_syntax = "tjp" augroup TaskJugglerSource " Remove all trailing white spaces from line ends when saving files " Note: This overwrites the s mark. autocmd BufWritePre *.tj[ip] mark s | %s/\s\+$//e | normal `s augroup END EOT end def normalize(str) str.gsub(/\./, '_') end end end