File indexing completed on 2024-05-05 04:01:50

0001 #!/usr/bin/perl -w
0002 
0003 # update script for kate-editor.org/syntax
0004 # SPDX-FileCopyrightText: 2020 Christoph Cullmann <cullmann@kde.org>
0005 # SPDX-License-Identifier: MIT
0006 
0007 # needed things
0008 use FindBin;
0009 use Cwd;
0010 use File::Basename;
0011 use File::Copy;
0012 use File::Path qw(make_path remove_tree);
0013 use XML::Parser;
0014 
0015 # be strict & warn
0016 use strict;
0017 use warnings;
0018 
0019 # we need as parameter both the source and the build directory
0020 my $sourceDir = shift;
0021 my $buildDir = shift;
0022 if (!defined($sourceDir) || !defined($buildDir)) {
0023     die "Not all arguments provided, valid call: update-kate-editor-org.pl <source directory> <build directory>\n";
0024 }
0025 
0026 # output settings
0027 print "Using source directory: $sourceDir\n";
0028 print "Using build directory: $buildDir\n";
0029 
0030 # switch to build directory, we do all our work there
0031 chdir($buildDir) || die "Failed to switch to build directory '$buildDir'!\n";
0032 
0033 # get kate-editor.org clone from invent.kde.org, update if already around
0034 if (-d "kate-editor-org") {
0035     print "Updating kate-editor.org clone...\n";
0036     system("git", "-C", "kate-editor-org", "pull") == 0 || die "Failed to pull kate-editor-org.git!\n";
0037 } else {
0038     print "Creating kate-editor.org clone...\n";
0039     system("git", "clone", "git\@invent.kde.org:websites/kate-editor-org.git") == 0 || die "Failed to clone kate-editor-org.git!\n";
0040 }
0041 
0042 #
0043 # update of syntax definitions
0044 # beside the pure update site generation, we will create some web site with examples for all highlightings
0045 #
0046 
0047 # try to get current frameworks version
0048 my $currentVersion;
0049 open (my $list, "<$sourceDir/CMakeLists.txt");
0050 for (<$list>) {
0051     if ((my $version) = /^set\(KF_VERSION "[0-9]+\.([0-9]+)\.[0-9]+"\)/) {
0052        $currentVersion = $version;
0053        last;
0054     }
0055 }
0056 close $list;
0057 if (!defined($currentVersion)) {
0058     die "Failed to determine current version of syntax-highlighting framework!\n"
0059 }
0060 
0061 # current maximal version
0062 print "Current version of syntax-highlighting: 5.$currentVersion\n";
0063 
0064 # purge old data in kate-editor.org clone
0065 my $staticSyntaxPath = "kate-editor-org/static/syntax";
0066 my $staticSyntaxPathData = "$staticSyntaxPath/data/syntax";
0067 remove_tree($staticSyntaxPath);
0068 if (-d $staticSyntaxPath) {
0069     die "Failed to delete '$staticSyntaxPath'!\n";
0070 }
0071 make_path($staticSyntaxPathData);
0072 if (! -d $staticSyntaxPathData) {
0073     die "Failed to create '$staticSyntaxPathData'!\n";
0074 }
0075 
0076 # collect all known syntax files from the generated resource file and copy them over
0077 open my $resourceFile, "<$buildDir/data/syntax-data.qrc";
0078 while (<$resourceFile>) {
0079     if ((my $file) = />(.*\.xml)<\/file>/) {
0080         copy($file, $staticSyntaxPathData) or die "Copy failed: $!";
0081     }
0082 }
0083 close $resourceFile;
0084 
0085 # copy over all html references as examples
0086 system("cp", "-rf", "$sourceDir/autotests/html", "$staticSyntaxPath/data/html") == 0 || die "Failed to copy HTML references!\n";
0087 
0088 # switch to kate-editor.org syntax directory now for post-processing
0089 chdir($staticSyntaxPath) || die "Failed to switch to '$staticSyntaxPath' directory!\n";
0090 
0091 # add new data to kate-editor.org git
0092 system("git", "add", "data") == 0 || die "Failed to add syntax files to git!\n";
0093 
0094 # setup XML parser with handler for start element
0095 my %languageAttributes = ();
0096 sub start_tag
0097 {
0098     # we only care for the language element, remember the attributes
0099     my($p, $tag, %attrs) = @_;
0100     if ($tag eq "language") {
0101         %languageAttributes = %attrs;
0102         $p->finish();
0103     }
0104 }
0105 my $parser = XML::Parser->new( Handlers => { Start => \&start_tag });
0106 
0107 # read all syntax files and remember for their version infos!
0108 print "Parsing XML syntax/*.xml files...\n";
0109 my %metaInfo;
0110 my %nameToFile;
0111 my $count = 0;
0112 foreach my $xmlFile (<data/syntax/*.xml>) {
0113     # parse the file
0114     %languageAttributes = ();
0115     $parser->parsefile( $xmlFile );
0116 
0117     # we need a name!
0118     my $name = $languageAttributes{'name'};
0119     if (!defined($name)) {
0120         print "Skipping $xmlFile as name attribute is missing.\n";
0121         next;
0122     }
0123 
0124     # if we have no versions set, we can't handle this file!
0125     my $version = $languageAttributes{'version'};
0126     if (!defined($version)) {
0127         print "Skipping $xmlFile as version attribute is missing.\n";
0128         next;
0129     }
0130     my $kateversion = $languageAttributes{'kateversion'};
0131     if (!defined($kateversion)) {
0132         print "Skipping $xmlFile as kateversion attribute is missing.\n";
0133         next;
0134     }
0135 
0136     # remember attributes
0137     # print "Remembering $xmlFile '$name' with version=$version & kateversion=$kateversion\n";
0138     foreach my $key (keys %languageAttributes) {
0139         $metaInfo{$xmlFile}{$key} = $languageAttributes{$key};
0140     }
0141 
0142     # remember section => name => file mapping
0143     $nameToFile{$languageAttributes{'section'}}{$name} = $xmlFile;
0144     ++$count;
0145 }
0146 
0147 # now: generate all needed update-*.xml files
0148 print "Generating XML update-*.xml files...\n";
0149 my $minorVersion = 0;
0150 while ($minorVersion <= $currentVersion) {
0151     # generate one update file
0152     my $cVersion = "5.$minorVersion";
0153     #print "Generation update-$cVersion.xml...\n";
0154     open (my $update, ">update-$cVersion.xml");
0155     print $update "<!DOCTYPE DEFINITIONS>\n";
0156     print $update "<DEFINITIONS>\n";
0157     foreach my $def (sort keys %metaInfo) {
0158         # is this definition allowed here?
0159         $_ = $metaInfo{$def}{kateversion};
0160         if ((my $version) = /[0-9]+\.([0-9]+)/) {
0161            next if ($version > $minorVersion);
0162         } else {
0163             next;
0164         }
0165         print $update "<Definition name=\"$metaInfo{$def}{name}\" url=\"https://kate-editor.org/syntax/$def\" version=\"$metaInfo{$def}{version}\"/>\n";
0166     }
0167     print $update "</DEFINITIONS>\n";
0168     close $update;
0169 
0170     # add to git
0171     system("git add update-$cVersion.xml") == 0 || die "Failed to add update-$cVersion.xml to git!\n";
0172 
0173     # next one
0174     ++$minorVersion;
0175 }
0176 
0177 # parse the html files to match them to the highlighting they belong to
0178 # we just search for the dark variants and derive the names for the non-dark from that
0179 print "Parsing HTML example syntax/data/html/*.html files...\n";
0180 my %nameToHTML;
0181 foreach my $htmlFile (<data/html/*.dark.html>, <data/html/.*.dark.html>) {
0182     my $name;
0183     open my $F, "<$htmlFile";
0184     while (<$F>) {
0185         if (($name) = /name="generator" content="KF5::SyntaxHighlighting - Definition \((.*)\) - Theme/) {
0186             last;
0187         }
0188     }
0189     close $F;
0190     if (defined($name)) {
0191         $htmlFile =~ s/\.dark\.html//;
0192         if (defined($nameToHTML{$name})) {
0193             die "Duplicated test output found for '$name' (".$nameToHTML{$name}." vs. ".$htmlFile.").\ntesthighlighter_test in the framework should not have allowed that!\n";
0194         }
0195         $nameToHTML{$name} = $htmlFile;
0196     } else {
0197         print "Skipping $htmlFile as proper generator meta information tag missing.\n";
0198     }
0199 }
0200 
0201 # for better l10n, only generate a YAML file containing syntax data
0202 # a Hugo template will be combined with the data to generate the overview page /syntax
0203 print "Generating syntax data in data/syntax.yaml...\n";
0204 make_path("../../data");
0205 my $syntax_path = "../../data/syntax.yaml";
0206 open (my $syntax_handle, ">$syntax_path");
0207 print $syntax_handle "# This file is auto-generated by \"make update_kate_editor_org\" in syntax-highlighting.git\n";
0208 foreach my $section (sort keys %nameToFile) {
0209     foreach my $name (sort keys %{$nameToFile{$section}}) {
0210         my $file = $nameToFile{$section}{$name};
0211         print $syntax_handle
0212             "- name: $name\n".
0213             "  section: $section\n".
0214             "  file: /syntax/$file\n";
0215 
0216         # link example output if existing
0217         if (defined($nameToHTML{$name})) {
0218             print $syntax_handle "  examples: [/syntax/".$nameToHTML{$name}.".html, /syntax/".$nameToHTML{$name}.".dark.html]\n";
0219         } else {
0220             print $syntax_handle "  examples: []\n";
0221         }
0222     }
0223 }
0224 close($syntax_handle);
0225 
0226 # add to git
0227 system("git add $syntax_path") == 0 || die "Failed to add $syntax_path to git!\n";
0228 
0229 #
0230 # update of themes web site
0231 # this will generate an overview of all shipped themes with an example
0232 #
0233 
0234 # switch back to build directory, we do all our work there
0235 chdir($buildDir) || die "Failed to switch to build directory '$buildDir'!\n";
0236 
0237 # purge old data in kate-editor.org clone
0238 my $staticThemePath = "kate-editor-org/static/themes";
0239 remove_tree($staticThemePath);
0240 if (-d $staticThemePath) {
0241     die "Failed to delete '$staticThemePath'!\n";
0242 }
0243 make_path($staticThemePath);
0244 if (! -d $staticThemePath) {
0245     die "Failed to create '$staticThemePath'!\n";
0246 }
0247 
0248 # copy over all html renderings as examples
0249 print "Updating theme example HTML files...\n";
0250 system("cp", "-rf", "autotests/theme.html.output", "$staticThemePath/html") == 0 || die "Failed to copy autotests/theme.html.output references!\n";
0251 
0252 # switch over to git again
0253 chdir($staticThemePath) || die "Failed to switch to '$staticThemePath' directory!\n";
0254 
0255 # collect all themes with their test case
0256 print "Parsing theme kate-editor-org/static/themes/html/*.html files...\n";
0257 my %themeToHTML;
0258 foreach my $htmlFile (<html/*.html>) {
0259     my $name;
0260     open my $F, "<$htmlFile";
0261     while (<$F>) {
0262         if (($name) = /name="generator" content="KF5::SyntaxHighlighting - Definition \(.*\) - Theme \((.*)\)"/) {
0263             last;
0264         }
0265     }
0266     close $F;
0267     if (defined($name)) {
0268         $themeToHTML{$name} = $htmlFile;
0269     } else {
0270         print "Skipping $htmlFile as proper generator meta information tag missing.\n";
0271     }
0272 }
0273 
0274 # create HTML snippets one can embed into a page from the theme HTML pages
0275 # we will hash the stuff from lower case name to real name + file for better output order below
0276 my %themeToHTMLSnippet;
0277 foreach my $name (sort keys %themeToHTML) {
0278     # get full file
0279     open my $F, "<$themeToHTML{$name}";
0280     my $fullFile = do { local $/; <$F> };
0281     close $F;
0282 
0283     # kill <body ...><pre> start and replace it with simple <pre> with body attribute
0284     $fullFile =~ s@.*<body style="(.*)"><pre>@<pre style="$1">@s;
0285 
0286     # kill ending </pre>... and replace it with simple </pre>
0287     $fullFile =~ s@</pre></body></html>@</pre>@g;
0288 
0289     # write snippet to disk
0290     my $snippetName = $themeToHTML{$name};
0291     $snippetName =~ s/\.html/-snippet.html/;
0292     open my $OF, ">$snippetName";
0293     print $OF $fullFile;
0294     close $OF;
0295     $themeToHTMLSnippet{lc($name)}{"name"} = $name;
0296     $themeToHTMLSnippet{lc($name)}{"file"} = $snippetName;
0297 }
0298 
0299 # add html files
0300 system("git", "add", "html") == 0 || die "Failed to add theme HTML files to git!\n";
0301 
0302 # for better l10n, only generate a YAML file containing theme data
0303 # a Hugo template will be combined with the data to generate the overview page /themes
0304 # we output sorted by lower case names as otherwise ayu and co. end up at the end...
0305 print "Generating theme data in data/themes.yaml...\n";
0306 my $themes_path = "../../data/themes.yaml";
0307 open (my $themes_handle, ">$themes_path");
0308 print $themes_handle "# This file is auto-generated by \"make update_kate_editor_org\" in syntax-highlighting.git\n";
0309 foreach my $lcName (sort keys %themeToHTMLSnippet) {
0310     my $name = $themeToHTMLSnippet{$lcName}{"name"};
0311     my $file = $themeToHTMLSnippet{$lcName}{"file"};
0312     print $themes_handle
0313         "- name: $name\n".
0314         "  file: /static/themes/$file\n";
0315 }
0316 close($themes_handle);
0317 
0318 # add to git
0319 system("git add $themes_path") == 0 || die "Failed to add $themes_path to git!\n";