#!/usr/bin/env perl use strict; use warnings; use POSIX qw(strftime); use JSON; use File::Basename; #my $cmake = "/home/pboettch/devel/upstream/cmake/build/bin/cmake"; my $cmake = "cmake"; my @variables; my @commands; my @properties; my @modules; my %keywords; # command => keyword-list # find cmake/Modules/ | sed -rn 's/.*CMakeDetermine(.+)Compiler.cmake/\1/p' | sort my @languages = qw(ASM ASM_MASM ASM_NASM C CSharp CUDA CXX Fortran Java RC Swift HIP); # unwanted upper-cases my %unwanted = map { $_ => 1 } qw(VS CXX IDE NOTFOUND NO_ DFOO DBAR NEW GNU); # cannot remove ALL - exists for add_custom_command # control-statements my %conditional = map { $_ => 1 } qw(if else elseif endif); my %loop = map { $_ => 1 } qw(foreach while endforeach endwhile); # decrecated my %deprecated = map { $_ => 1 } qw(build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file); # add some (popular) modules push @modules, "ExternalProject", "FetchContent"; # variables open(CMAKE, "$cmake --help-variable-list|") or die "could not run cmake"; while () { chomp; if (/<(.*?)>/) { if ($1 eq 'LANG') { foreach my $lang (@languages) { (my $V = $_) =~ s/<.*>/$lang/; push @variables, $V; } next } else { next; # skip if containing < or > } } push @variables, $_; } close(CMAKE); # transform all variables in a hash - to be able to use exists later on my %variables = map { $_ => 1 } @variables; # commands open(CMAKE, "$cmake --help-command-list|"); while (my $cmd = ) { chomp $cmd; push @commands, $cmd; } close(CMAKE); # now generate a keyword-list per command foreach my $cmd (@commands) { my @word = extract_upper("$cmake --help-command $cmd|"); next if scalar @word == 0; $keywords{$cmd} = [ sort keys %{ { map { $_ => 1 } @word } } ]; } # and now for modules foreach my $mod (@modules) { my @word = extract_upper("$cmake --help-module $mod|"); next if scalar @word == 0; $keywords{$mod} = [ sort keys %{ { map { $_ => 1 } @word } } ]; } # and now for generator-expressions my @generator_expr = extract_upper("$cmake --help-manual cmake-generator-expressions |"); # properties open(CMAKE, "$cmake --help-property-list|"); while () { next if /\ chomp; push @properties, $_; } close(CMAKE); # transform all properties in a hash my %properties = map { $_ => 1 } @properties; # read in manually written files my $modules_dir = dirname(__FILE__) . "/modules"; opendir(DIR, $modules_dir) || die "can't opendir $modules_dir: $!"; my @json_files = grep { /\.json$/ && -f "$modules_dir/$_" } readdir(DIR); closedir DIR; foreach my $file (@json_files) { local $/; # Enable 'slurp' mode open my $fh, "<", $modules_dir."/".$file; my $json = <$fh>; close $fh; my $mod = decode_json($json); foreach my $var (@{$mod->{variables}}) { $variables{$var} = 1; } while (my ($cmd, $keywords) = each %{$mod->{commands}}) { $keywords{$cmd} = [ sort @{$keywords} ]; } } # version open(CMAKE, "$cmake --version|"); my $version = 'unknown'; while () { chomp; $version = $_ if /cmake version/; } close(CMAKE); # generate cmake.vim open(IN, "syntax/cmake.vim") or die "could not write to syntax/cmake.vim"; my @keyword_hi; while() { if (m/\@([A-Z0-9_]+)\@/) { # match for @SOMETHING@ if ($1 eq "COMMAND_LIST") { # do not include "special" commands in this list my @tmp = grep { ! exists $conditional{$_} and ! exists $loop{$_} and ! exists $deprecated{$_} } @commands; print_list(\*OUT, @tmp); } elsif ($1 eq "VARIABLE_LIST") { print_list(\*OUT, keys %variables); } elsif ($1 eq "MODULES") { print_list(\*OUT, @modules); } elsif ($1 eq "GENERATOR_EXPRESSIONS") { print_list(\*OUT, @generator_expr); } elsif ($1 eq "CONDITIONALS") { print_list(\*OUT, keys %conditional); } elsif ($1 eq "LOOPS") { print_list(\*OUT, keys %loop); } elsif ($1 eq "DEPRECATED") { print_list(\*OUT, keys %deprecated); } elsif ($1 eq "PROPERTIES") { print_list(\*OUT, keys %properties); } elsif ($1 eq "KEYWORDS") { foreach my $k (sort keys %keywords) { print OUT "syn keyword cmakeKW$k contained\n"; print_list(\*OUT, @{$keywords{$k}}); print OUT "\n"; push @keyword_hi, "hi def link cmakeKW$k ModeMsg"; } } elsif ($1 eq "KEYWORDS_HIGHLIGHT") { print OUT join("\n", @keyword_hi), "\n"; } elsif ($1 eq "VERSION") { $_ =~ s/\@VERSION\@/$version/; print OUT $_; } elsif ($1 eq "DATE") { my $date = strftime "%Y %b %d", localtime; $_ =~ s/\@DATE\@/$date/; print OUT $_; } else { print "ERROR do not know how to replace $1\n"; } } else { print OUT $_; } } close(IN); close(OUT); sub extract_upper { my $input = shift; my @word; open(KW, $input); while () { foreach my $w (m/\b([A-Z_]{2,})\b/g) { next if exists $variables{$w} or # skip if it is a variable exists $unwanted{$w} or # skip if not wanted grep(/$w/, @word); # skip if already in array push @word, $w; } } close(KW); return @word; } sub print_list { my $O = shift; my $indent = " " x 12 . "\\ "; print $O $indent, join("\n" . $indent, sort @_), "\n"; }