diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec6951e --- /dev/null +++ b/.gitignore @@ -0,0 +1,327 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/CustomAnalysisRules.Test.ruleset b/CustomAnalysisRules.Test.ruleset new file mode 100644 index 0000000..64485ad --- /dev/null +++ b/CustomAnalysisRules.Test.ruleset @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CustomAnalysisRules.ruleset b/CustomAnalysisRules.ruleset new file mode 100644 index 0000000..c6f28c0 --- /dev/null +++ b/CustomAnalysisRules.ruleset @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..eabd9b7 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,44 @@ + + + true + + Full + 7.3 + true + false + $(EnableSourceLink) + + true + + + + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + false + $(MSBuildThisFileDirectory)\CustomAnalysisRules.Test.ruleset + + + + + true + $(MSBuildThisFileDirectory)\CustomAnalysisRules.ruleset + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c96bc6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 James231 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c209350 --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +# Simple Version Control + +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MLD56V6HQWCKU&source=url) + + + +This is a .NET Standard Library for setting up very basic version control in your .NET applications. It comes with a WPF app to quickly create your new version information. + +:star: :star: :star: And if you like it ... please star it! :star: :star: :star: + +## Gui Screenshots + +Click for full size. + +[](https://cdn.jam-es.com/img/simple-version-control/screen1.png) + +[](https://cdn.jam-es.com/img/simple-version-control/screen2.png) + +[](https://cdn.jam-es.com/img/simple-version-control/screen3.png) + +## How to Use + +Install the WPF app from the [GitHub Releases Page](https://github.com/James231/Simple-Version-Control/releases). Use the app to produce a set of version control JSON files. You should use the app to update these files every time a new version is released. + +**Note:** It is possible to write the version control files by hand, but I strongly recommend you use the app. + +Next you need somewhere to host your version control files. I recommend a free static web host like [GitHub Pages](https://pages.github.com/), [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/), or [Netlify](https://www.netlify.com/). My preferred choice is [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/). + +Once you have created and hosted the files to a url like ... +``` +https://example.com/app/vc/changelog.json +``` +... then you can add the version control to your app. For example, you could add a 'Check For Updates' button. + +## Add Version Control to Your App + +Within a console app, WinForms, WPF app, library or any other .NET project you can add version control information or checks. + +Start by installing the following SimpleVersionControl NuGet package. This can be done using the NuGet package manager with the following command: +``` +Install-Package SimpleVersionControl +``` + +Then within a C# file add: +```cs +using SimpleVersionControl; +``` + +Then the most important functionality is demonstrated in the code below: +```cs +// Create instance of VersionController by passing in this version of the application, and the URL of the directory containing changelog file: +VersionController versionController = new VersionController("1.0.1", "https://example.com/app/vc/"); + +// Check this is the latest version +bool isLatestVersion = await versionController.IsLatestVersion(); + +// If not latest, you can check this version is still meant to function correctly +bool isFunctioningVersion = await versionController.IsFunctioningVersion(); + +// Receive a list of all changes between two versions +// These are actually references to changes and you need to use ChangeRef.GetChange to get the Change object +IEnumerable changes = await versionController.GetChangesBetween("1.0.0", "1.0.1"); +foreach(ChangeRef changeRef in changes) { + Change change = await changeRef.GetChange(); + Console.WriteLine($"Change Title: {change.Title}"); + Console.WriteLine($"Change Description: {change.Description}"); + Console.WriteLine($"Change Release Version: {change.ReleaseVersion.VersionName}"); +} + +// The ChangeLog object contains a list of all versions that have been released +// We can list version properties like this: +ChangeLog changeLog = await versionController.GetChangeLog(); +foreach (VersionRef versionRef in changeLog.Versions) { + Version version = await versionRef.GetVersion(); + Console.WriteLine($"Version Name: {version.VersionName}"); + Console.WriteLine($"Version Description: {version.Description}"); + Console.WriteLine($"Version Download Link: {version.DownloadLink}"); + Console.WriteLine($"Version Release Date: {version.ReleaseDate}"); + // You can get all changes in a version with version.Changes +} + +// Get individual versions with: +VersionRef firstAppVersionRef = await versionController.GetFirstVersionRef(); +Version latestAppVersionRef = await versionController.GetLatestVersion(); +VersionRef specificVersionRef = await versionController.GetVersionRef("1.0.1b4"); +// Convert references to Version objects to get all the properties +Version specificVersion = await specificVersionRef.GetVersion(); + +// Get the current Version object representing this application version +Version curVersion = await versionController.GetVersion(); + +// ChangeLog, Version and Change objects can all have additional data stored within them (set in the WPF app) +// You can access this data by deserializing the AdditionalData property (it is a JObject) +// For example, to retrieve additional data from a version +class ExtraVersionData { + public int Importance { get; set; } +} +ExtraVersionData extraData = curVersion.AdditionalData.ToObject(); + +// You could use this to order lists of versions or changes using Linq: +List> getVersionTasks = changeLog.Versions.Select(async v => await v.GetVersion()).ToList(); +IEnumerable versions = await Task.WhenAll(getVersionTasks); +versions.OrderBy(v => v.AdditionalData.ToObject().Importance); +// It is gerenally a good idea to surround this in try{}catch{} in case ToObject throws an error +``` + +## License + +This code is released under MIT license. This means you can use this for whatever you want. Modify, distribute, sell, fork, and use this as much as you like. Both for personal and commercial use. I hold no responsibility if anything goes wrong. + +If you use this, you don't need to refer to this repo, or give me any kind of credit but it would be appreciated. At least a :star: would be nice. + +It took a lot of work to make this available for free. If you are feeling more generous, perhaps you could consider donating? + +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MLD56V6HQWCKU&source=url) + +## Contributing + +Pull Requests are welcome. But, note that by creating a pull request you are giving me permission to merge your code and release it under the MIT license mentioned above. At no point will you be able to withdraw merged code from the repository, or change the license under which it has been made available. + +## References + +This wouldn't have been possible without ... + +[Material Design In Xaml](http://materialdesigninxaml.net/) - The WPF styles used in this app. + +[AvalonEdit](http://avalonedit.net/) - The code editor WPF control used for the JSON editing in the app. + +[AvalonEditHighlightingThemes](https://github.com/Dirkster99/AvalonEditHighlightingThemes) - Implementation of Themes in AvalonEdit. Used for light/dark JSON editing themes. + +[Json.NET](https://www.newtonsoft.com/json) - JSON serializer. + +[Wix Toolset](https://wixtoolset.org/) - Used to create the `.msi` installer. + +... and obvious credit to Microsoft for C#, WPF, .NET, and the best OS in existence :) \ No newline at end of file diff --git a/SimpleVersionControl.sln b/SimpleVersionControl.sln new file mode 100644 index 0000000..f1687a9 --- /dev/null +++ b/SimpleVersionControl.sln @@ -0,0 +1,79 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30330.147 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleVersionControl", "src\SimpleVersionControl\SimpleVersionControl.csproj", "{0DF4934A-83B0-4EE2-9486-892F6B22648C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleVersionControl.App", "src\SimpleVersionControl.App\SimpleVersionControl.App.csproj", "{94FB3269-CC7C-4412-A35E-6FADF9431B40}" +EndProject +Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "StartMenuManager.GUI.Installer", "src\SimpleVersionControl.App.Installer\StartMenuManager.GUI.Installer.wixproj", "{B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleVersionControl.Example", "src\SimpleVersionControl.Example\SimpleVersionControl.Example.csproj", "{0819FE23-85DE-42A0-BE15-37DEDF55AD24}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HL", "src\HL\HL.csproj", "{26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TextEditLib", "src\TextEditLib\TextEditLib.csproj", "{5AD36454-7653-4282-9B9F-2183F0064754}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Debug|x86.ActiveCfg = Debug|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Debug|x86.Build.0 = Debug|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Release|Any CPU.Build.0 = Release|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Release|x86.ActiveCfg = Release|Any CPU + {0DF4934A-83B0-4EE2-9486-892F6B22648C}.Release|x86.Build.0 = Release|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Debug|x86.ActiveCfg = Debug|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Debug|x86.Build.0 = Debug|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Release|Any CPU.Build.0 = Release|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Release|x86.ActiveCfg = Release|Any CPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40}.Release|x86.Build.0 = Release|Any CPU + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Debug|Any CPU.ActiveCfg = Debug|x86 + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Debug|x86.ActiveCfg = Debug|x86 + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Debug|x86.Build.0 = Debug|x86 + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Release|Any CPU.ActiveCfg = Release|x86 + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Release|x86.ActiveCfg = Release|x86 + {B7CBB2B3-65E2-44FB-AAD6-9BD76884D09D}.Release|x86.Build.0 = Release|x86 + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Debug|x86.ActiveCfg = Debug|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Debug|x86.Build.0 = Debug|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Release|Any CPU.Build.0 = Release|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Release|x86.ActiveCfg = Release|Any CPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24}.Release|x86.Build.0 = Release|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Debug|x86.ActiveCfg = Debug|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Debug|x86.Build.0 = Debug|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Release|Any CPU.Build.0 = Release|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Release|x86.ActiveCfg = Release|Any CPU + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4}.Release|x86.Build.0 = Release|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Debug|x86.ActiveCfg = Debug|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Debug|x86.Build.0 = Debug|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Release|Any CPU.Build.0 = Release|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Release|x86.ActiveCfg = Release|Any CPU + {5AD36454-7653-4282-9B9F-2183F0064754}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {37ED5A5D-0B95-42B3-98E4-6FBBEF19EC01} + EndGlobalSection +EndGlobal diff --git a/img/icon-256x256.ico b/img/icon-256x256.ico new file mode 100644 index 0000000..32492ec Binary files /dev/null and b/img/icon-256x256.ico differ diff --git a/img/icon-256x256.png b/img/icon-256x256.png new file mode 100644 index 0000000..e6b783b Binary files /dev/null and b/img/icon-256x256.png differ diff --git a/img/icon.svg b/img/icon.svg new file mode 100644 index 0000000..b5e3b34 --- /dev/null +++ b/img/icon.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + v1 + + diff --git a/src/HL/AssemblyInfo.cs b/src/HL/AssemblyInfo.cs new file mode 100644 index 0000000..9660537 --- /dev/null +++ b/src/HL/AssemblyInfo.cs @@ -0,0 +1,17 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; + +#pragma warning disable + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/src/HL/HL.csproj b/src/HL/HL.csproj new file mode 100644 index 0000000..7d4c92d --- /dev/null +++ b/src/HL/HL.csproj @@ -0,0 +1,135 @@ + + + + net4;netcoreapp3.0 + true + 1.0.4 + 1.0.4 + 1.0.4 + Open Source + Dirkster.HL + 2019-2020 + This assembly implements a docking layout system for WPF. + + true + https://github.com/Dirkster99/HL + https://github.com/Dirkster99/HL + Dirkster.HL + https://github.com/Dirkster99/HL + LICENSE + + icon.png + avalonedit dark-theme light-theme theming highlighting + Mutlitargetting NetCore3 and Net 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + Designer + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/src/HL/HighlightingTheme/GlobalStyle.cs b/src/HL/HighlightingTheme/GlobalStyle.cs new file mode 100644 index 0000000..d2221eb --- /dev/null +++ b/src/HL/HighlightingTheme/GlobalStyle.cs @@ -0,0 +1,139 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.HighlightingTheme +{ + using HL.Xshtd.interfaces; + using System.Windows.Media; + + /// + /// Implements an object that holds general color and style definitions for the + /// Editor. These style definitions are usually non-highlighting language specific + /// (eg Hyperlink color) and can overwrite existing WPF definition (eg background or + /// foreground color) + /// + public class GlobalStyle : AbstractFreezable, IFreezable + { + #region fields + private string _TypeName; + private Color? _Foregroundcolor; + private Color? _Backgroundcolor; + private Color? _Bordercolor; + #endregion fields + + #region ctors + /// + /// Construct a named (eg. 'Comment') WordStyle object + /// + /// + public GlobalStyle(string typeName) + : this() + { + this.TypeName = typeName; + } + + /// + /// Hidden standard constructor + /// + protected GlobalStyle() + { + this.TypeName = string.Empty; + _Foregroundcolor = null; + _Backgroundcolor = null; + _Bordercolor = null; + } + #endregion ctors + + #region properties + /// + /// Typed name of object + /// + /// (eg 'DefaultStyle', 'NonPrintableCharacter' ..., + /// (this is usually the key in a collection of these styles) + /// + public string TypeName + { + get + { + return _TypeName; + } + set + { + if (IsFrozen) + throw new System.InvalidOperationException("Property is already frozen."); + + _TypeName = value; + } + } + + /// + /// Get/set brush definition for the foreground used in this style + /// + public Color? foregroundcolor + { + get + { + return _Foregroundcolor; + } + set + { + if (IsFrozen) + throw new System.InvalidOperationException("Property is already frozen."); + + _Foregroundcolor = value; + } + } + + /// + /// Get/set brush definition for the background used in this style + /// + public Color? backgroundcolor + { + get + { + return _Backgroundcolor; + } + set + { + if (IsFrozen) + throw new System.InvalidOperationException("Property is already frozen."); + + _Backgroundcolor = value; + } + } + + /// + /// Get/set brush definition for the border used in this style + /// + public Color? bordercolor + { + get + { + return _Bordercolor; + } + set + { + if (IsFrozen) + throw new System.InvalidOperationException("Property is already frozen."); + + _Bordercolor = value; + } + } + #endregion properties + + #region methods + /// + /// Returns a string that represents the current object. + /// + /// + public override string ToString() + { + return "[" + (string.IsNullOrEmpty(this.TypeName) ? string.Empty : this.TypeName) + "]"; + } + #endregion methods + } +} diff --git a/src/HL/HighlightingTheme/SyntaxDefinition.cs b/src/HL/HighlightingTheme/SyntaxDefinition.cs new file mode 100644 index 0000000..fafe1ef --- /dev/null +++ b/src/HL/HighlightingTheme/SyntaxDefinition.cs @@ -0,0 +1,130 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.HighlightingTheme +{ + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using ICSharpCode.AvalonEdit.Utils; + using System; + using System.Collections.Generic; + + /// + /// Implements the object that keeps track of each syntax definition reference + /// within a highlighting theme definition. + /// + public class SyntaxDefinition : AbstractFreezable, IFreezable + { + #region fields + string _Name; + private readonly Dictionary _NamedHighlightingColors; + #endregion fields + + #region ctors + /// + /// Class constructor + /// + public SyntaxDefinition(string paramName) + : this() + { + this._Name = paramName; + } + + /// + /// Class constructor + /// + public SyntaxDefinition() + { + this.Extensions = new NullSafeCollection(); + _NamedHighlightingColors = new Dictionary(); + } + #endregion ctors + + #region properties + /// + /// Gets/Sets the name of the color. + /// + public string Name + { + get + { + return _Name; + } + set + { + if (IsFrozen) + throw new InvalidOperationException(); + + _Name = value; + } + } + + /// + /// Gets the associated extensions. + /// + public IList Extensions { get; private set; } + + /// + /// Gets an enumeration of all highlighting colors that are defined + /// for this highlighting pattern (eg. C#) as part of a highlighting theme (eg 'True Blue'). + /// + public IEnumerable NamedHighlightingColors + { + get + { + return _NamedHighlightingColors.Values; + } + } + #endregion properties + + #region methods + /// + /// Returns a string that represents the current object. + /// + /// + public override string ToString() + { + return "[" + GetType().Name + " " + (string.IsNullOrEmpty(this.Name) ? string.Empty : this.Name) + "]"; + } + + /// + /// Gets a named color definition or null. + /// + /// + /// + public HighlightingColor ColorGet(string name) + { + HighlightingColor color; + if (_NamedHighlightingColors.TryGetValue(name, out color)) + return color; + + return null; + } + + /// + /// Adds another named color definition. + /// Exceptions: + /// + /// key is null. + /// + /// + /// An element with the same key already exists in the System.Collections.Generic.Dictionary`2. + /// + /// + public void ColorAdd(HighlightingColor color) + { + _NamedHighlightingColors.Add(color.Name, color); + } + + internal void ColorReplace(string name, HighlightingColor themeColor) + { + _NamedHighlightingColors.Remove(name); + _NamedHighlightingColors.Add(name, themeColor); + } + #endregion methods + } +} diff --git a/src/HL/Interfaces/IHLTheme.cs b/src/HL/Interfaces/IHLTheme.cs new file mode 100644 index 0000000..f99b7bb --- /dev/null +++ b/src/HL/Interfaces/IHLTheme.cs @@ -0,0 +1,123 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using System.Collections.ObjectModel; + using HL.HighlightingTheme; + using HL.Xshtd; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + + /// + /// Defines a highlighting theme which is based on a WPF theme (eg. 'Light') + /// with a corresponding set of highlighting definitions (eg. 'XML', 'C#' etc) + /// to ensure that highlightings are correct in the contecxt of + /// (different background colors) WPF themes. + /// + public interface IHLTheme + { + #region properties + /// + /// Gets the display independent key value that should by unique in an + /// overall collection of highlighting themes and should be used for retrieval purposes. + /// + string Key { get; } + + /// + /// Gets the prefix of the XSHD resources that should be used to lookup + /// the actual resource for this theme. + /// + /// This property is null for a derived highlighting theme since finding its + /// base highlighting should by performed through + /// and the corresponding property of that entry. + /// + string HLBasePrefix { get; } + + /// + /// Gets the name of theme (eg. 'Dark' or 'Light' which is used as + /// the base of a derived highlighting theme. + /// + /// This property has the same value as the property + /// if the highlighting is GENERIC (since these highlightings come without + /// additional theme resources). + /// + string HLBaseKey { get; } + + /// + /// Gets the prefix of the resource under which a theme resource definition + /// file xshTd can be found (eg 'HL.Resources.Themes'). + /// + string HLThemePrefix { get; } + + /// + /// Gets the file name under which a theme resource definition + /// file xshTd can be found (eg 'Dark.xshtd'). + /// + string HLThemeFileName { get; } + + /// + /// Gets the name of theme (eg. 'Dark', 'Light' or 'True Blue' for display purposes in the UI. + /// + string DisplayName { get; } + + /// + /// Gets a copy of all highlightings defined in this object. + /// + ReadOnlyCollection HighlightingDefinitions { get; } + + /// + /// Gets the theme highlighting definition for this theme + /// or null (highlighting definition is generic and not based on a theme). + /// + IHighlightingThemeDefinition HlTheme { get; } + + /// + /// Gets/sets whether built-in themes have already been registered or not + /// Use this to avoid registration of built-in themes twice for one and the + /// same highlighting theme. + /// + bool IsBuiltInThemesRegistered { get; set; } + #endregion properties + + #region methods + /// + /// Gets the highlighting definition by name, or null if it is not found. + /// + IHighlightingDefinition GetDefinition(string name); + + /// + /// Gets a highlighting definition by extension. + /// Returns null if the definition is not found. + /// + IHighlightingDefinition GetDefinitionByExtension(string extension); + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// The highlighting definition. + void RegisterHighlighting(string name, string[] extensions, IHighlightingDefinition highlighting); + + /// + /// Gets the highlighting theme definition by name, or null if it is not found. + /// + /// + SyntaxDefinition GetThemeDefinition(string highlightingName); + + /// + /// Converts a XSHD reference from namespace prefix and themename + /// into a object and returns it. + /// + /// + /// + /// + XhstdThemeDefinition ResolveHighLightingTheme(string hLPrefix, string hLThemeName); + #endregion methods + } +} \ No newline at end of file diff --git a/src/HL/Interfaces/IThemedHighlightingManager.cs b/src/HL/Interfaces/IThemedHighlightingManager.cs new file mode 100644 index 0000000..81eb050 --- /dev/null +++ b/src/HL/Interfaces/IThemedHighlightingManager.cs @@ -0,0 +1,72 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Interfaces +{ + using HL.Manager; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Collections.ObjectModel; + + /// + /// Defines a Highlighting Manager that associates syntax highlighting definitions with file extentions + /// (*.cs -> 'C#') with consideration of the current WPF App theme + /// + /// Extension App Theme SyntaxHighlighter + /// (*.cs + 'Dark') -> 'C#' (with color definitions for 'Dark') + /// + public interface IThemedHighlightingManager : IHighlightingDefinitionReferenceResolver, + IHighlightingThemeDefinitionReferenceResolver + { + #region properties + /// + /// Gets the current highlighting theme (eg 'Light' or 'Dark') that should be used as + /// a base for the syntax highlighting in AvalonEdit. + /// + IHLTheme CurrentTheme { get; } + #endregion properties + + #region methods + /// + /// Gets a copy of all highlightings. + /// + ReadOnlyCollection HighlightingDefinitions { get; } + + /// + /// Gets a highlighting definition by extension. + /// Returns null if the definition is not found. + /// + IHighlightingDefinition GetDefinitionByExtension(string extension); + + /// + /// Registers a highlighting definition for the . + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// The highlighting definition. + void RegisterHighlighting(string name, string[] extensions, IHighlightingDefinition highlighting); + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// A function that loads the highlighting definition. + void RegisterHighlighting(string name, string[] extensions, Func lazyLoadedHighlighting); + + /// + /// Resets the highlighting theme based on the name of the WPF App Theme + /// (eg: WPF APP Theme 'Dark' -> Resolve highlighting 'C#' to 'Dark'->'C#') + /// + /// Throws an if the WPF APP theme is not known. + /// + /// + void SetCurrentTheme(string name); + #endregion methods + } +} diff --git a/src/HL/LICENSE b/src/HL/LICENSE new file mode 100644 index 0000000..7d7cb0e --- /dev/null +++ b/src/HL/LICENSE @@ -0,0 +1,9 @@ +Copyright 2019-2020 Dirkster99 + +MIT License (https://opensource.org/licenses/MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/HL/Manager/BusyManager.cs b/src/HL/Manager/BusyManager.cs new file mode 100644 index 0000000..e98d56c --- /dev/null +++ b/src/HL/Manager/BusyManager.cs @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using System; + using System.Collections.Generic; + + /// + /// This class is used to prevent stack overflows by representing a 'busy' flag + /// that prevents reentrance when another call is running. + /// However, using a simple 'bool busy' is not thread-safe, so we use a + /// thread-static BusyManager. + /// + internal static class BusyManager + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", + Justification = "Should always be used with 'var'")] + public struct BusyLock : IDisposable + { + public static readonly BusyLock Failed = new BusyLock(null); + + readonly List objectList; + + internal BusyLock(List objectList) + { + this.objectList = objectList; + } + + public bool Success + { + get { return objectList != null; } + } + + public void Dispose() + { + if (objectList != null) + { + objectList.RemoveAt(objectList.Count - 1); + } + } + } + + [ThreadStatic] static List _activeObjects; + + public static BusyLock Enter(object obj) + { + List activeObjects = _activeObjects; + if (activeObjects == null) + activeObjects = _activeObjects = new List(); + for (int i = 0; i < activeObjects.Count; i++) + { + if (activeObjects[i] == obj) + return BusyLock.Failed; + } + activeObjects.Add(obj); + return new BusyLock(activeObjects); + } + } +} diff --git a/src/HL/Manager/DefaultHighlightingManager.cs b/src/HL/Manager/DefaultHighlightingManager.cs new file mode 100644 index 0000000..0898aae --- /dev/null +++ b/src/HL/Manager/DefaultHighlightingManager.cs @@ -0,0 +1,170 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.HighlightingTheme; + using HL.Resources; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Diagnostics; + using System.IO; + using System.Xml; + + /// + /// Implements a default highlighting manager for + /// AvalonEdit based themable syntax highlighting definitions. + /// + internal sealed class DefaultHighlightingManager : ThemedHighlightingManager + { + #region ctors + /// + /// Static class constructor + /// + static DefaultHighlightingManager() + { + var defaultManager = new DefaultHighlightingManager(); + + var theme = new HLTheme("Dark", "Light", "Dark", + HL_THEMES_NAMESPACE_ROOT, "Dark.xshtd", defaultManager); + defaultManager.ThemedHighlightingAdd(theme.Key, theme); + + theme = new HLTheme("Light", HL_GENERIC_NAMESPACE_ROOT, "Light"); + defaultManager.ThemedHighlightingAdd(theme.Key, theme); + + // Setup default theme without registration of Highlightings + defaultManager.SetCurrentThemeInternal(theme.Key); + + theme = new HLTheme("TrueBlue", "Light", "True Blue", + HL_THEMES_NAMESPACE_ROOT, "TrueBlue.xshtd", defaultManager); + defaultManager.ThemedHighlightingAdd(theme.Key, theme); + + theme = new HLTheme("VS2019_Dark", "Light", "VS2019 Dark", + HL_THEMES_NAMESPACE_ROOT, "VS2019_Dark.xshtd", defaultManager); + defaultManager.ThemedHighlightingAdd(theme.Key, theme); + + HLResources.RegisterBuiltInHighlightings(defaultManager, defaultManager.CurrentTheme); + + Instance = defaultManager; + } + + /// + /// Default class constructor + /// + public DefaultHighlightingManager() + : base() + { + } + #endregion ctors + + /// + /// Gets an instance of a object. + /// + public new static readonly DefaultHighlightingManager Instance; + + /// + /// Registering a built-in highlighting including highlighting themes (if any). + /// + /// + /// + /// + /// + internal void RegisterHighlighting(IHLTheme theme, + string name, + string[] extensions, + string resourceName) + { + try + { +#if DEBUG + // don't use lazy-loading in debug builds, show errors immediately + ICSharpCode.AvalonEdit.Highlighting.Xshd.XshdSyntaxDefinition xshd; + using (Stream s = HLResources.OpenStream(GetPrefix(CurrentTheme.HLBaseKey), resourceName)) + { + using (XmlTextReader reader = new XmlTextReader(s)) + { + xshd = HighlightingLoader.LoadXshd(reader, false); + } + } + Debug.Assert(name == xshd.Name); + if (extensions != null) + Debug.Assert(System.Linq.Enumerable.SequenceEqual(extensions, xshd.Extensions)); + else + Debug.Assert(xshd.Extensions.Count == 0); + + var hlTheme = theme.HlTheme; + SyntaxDefinition themedHighlights = null; + + if (hlTheme != null) + { + themedHighlights = hlTheme.GetNamedSyntaxDefinition(name); + } + + // round-trip xshd: + // string resourceFileName = Path.Combine(Path.GetTempPath(), resourceName); + // using (XmlTextWriter writer = new XmlTextWriter(resourceFileName, System.Text.Encoding.UTF8)) { + // writer.Formatting = Formatting.Indented; + // new Xshd.SaveXshdVisitor(writer).WriteDefinition(xshd); + // } + // using (FileStream fs = File.Create(resourceFileName + ".bin")) { + // new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, xshd); + // } + // using (FileStream fs = File.Create(resourceFileName + ".compiled")) { + // new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(fs, Xshd.HighlightingLoader.Load(xshd, this)); + // } + + base.RegisterHighlighting(name, extensions, + HighlightingLoader.Load(themedHighlights, xshd, this)); +#else + base.RegisterHighlighting(name, extensions, LoadHighlighting(theme, name, resourceName)); +#endif + } + catch (HighlightingDefinitionInvalidException ex) + { + throw new InvalidOperationException("The built-in highlighting '" + name + "' is invalid.", ex); + } + } + + /// + /// Gets a function that is used to load highlighting definition in a delayed/defered way + /// (usually active only when 'Release' is configured). + /// + /// + /// + /// + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", + Justification = "LoadHighlighting is used only in release builds")] + Func LoadHighlighting(IHLTheme theme, string name, string resourceName) + { + Func func = delegate + { + ICSharpCode.AvalonEdit.Highlighting.Xshd.XshdSyntaxDefinition xshd; + using (Stream s = HLResources.OpenStream(GetPrefix(CurrentTheme.HLBaseKey), resourceName)) + { + using (XmlTextReader reader = new XmlTextReader(s)) + { + // in release builds, skip validating the built-in highlightings + xshd = HighlightingLoader.LoadXshd(reader, true); + } + } + + var hlTheme = theme.HlTheme; + SyntaxDefinition themedHighlights = null; + + if (hlTheme != null) + { + themedHighlights = hlTheme.GetNamedSyntaxDefinition(name); + } + + return HighlightingLoader.Load(themedHighlights, xshd, this); + }; + + return func; + } + } +} diff --git a/src/HL/Manager/DelayLoadedHighlightingDefinition.cs b/src/HL/Manager/DelayLoadedHighlightingDefinition.cs new file mode 100644 index 0000000..5081982 --- /dev/null +++ b/src/HL/Manager/DelayLoadedHighlightingDefinition.cs @@ -0,0 +1,120 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Collections.Generic; + + internal sealed class DelayLoadedHighlightingDefinition : IHighlightingDefinition + { + readonly object lockObj = new object(); + readonly string name; + Func lazyLoadingFunction; + IHighlightingDefinition definition; + Exception storedException; + + public DelayLoadedHighlightingDefinition(string name, Func lazyLoadingFunction) + { + this.name = name; + this.lazyLoadingFunction = lazyLoadingFunction; + } + + public string Name + { + get + { + if (name != null) + return name; + else + return GetDefinition().Name; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", + Justification = "The exception will be rethrown")] + IHighlightingDefinition GetDefinition() + { + Func func; + lock (lockObj) + { + if (this.definition != null) + return this.definition; + func = this.lazyLoadingFunction; + } + Exception exception = null; + IHighlightingDefinition def = null; + try + { + using (var busyLock = BusyManager.Enter(this)) + { + if (!busyLock.Success) + throw new InvalidOperationException("Tried to create delay-loaded highlighting definition recursively. Make sure the are no cyclic references between the highlighting definitions."); + def = func(); + } + if (def == null) + throw new InvalidOperationException("Function for delay-loading highlighting definition returned null"); + } + catch (Exception ex) + { + exception = ex; + } + lock (lockObj) + { + this.lazyLoadingFunction = null; + if (this.definition == null && this.storedException == null) + { + this.definition = def; + this.storedException = exception; + } + if (this.storedException != null) + throw new HighlightingDefinitionInvalidException("Error delay-loading highlighting definition", this.storedException); + return this.definition; + } + } + + public HighlightingRuleSet MainRuleSet + { + get + { + return GetDefinition().MainRuleSet; + } + } + + public HighlightingRuleSet GetNamedRuleSet(string name) + { + return GetDefinition().GetNamedRuleSet(name); + } + + public HighlightingColor GetNamedColor(string name) + { + return GetDefinition().GetNamedColor(name); + } + + public IEnumerable NamedHighlightingColors + { + get + { + return GetDefinition().NamedHighlightingColors; + } + } + + public override string ToString() + { + return this.Name; + } + + public IDictionary Properties + { + get + { + return GetDefinition().Properties; + } + } + } +} diff --git a/src/HL/Manager/ExtensionMethods.cs b/src/HL/Manager/ExtensionMethods.cs new file mode 100644 index 0000000..ecde552 --- /dev/null +++ b/src/HL/Manager/ExtensionMethods.cs @@ -0,0 +1,242 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + //// using System.Windows; + //// using System.Windows.Controls; + //// using System.Windows.Media; + using System.Xml; + + static class ExtensionMethods + { + #region Epsilon / IsClose / CoerceValue + /// + /// Epsilon used for IsClose() implementations. + /// We can use up quite a few digits in front of the decimal point (due to visual positions being relative to document origin), + /// and there's no need to be too accurate (we're dealing with pixels here), + /// so we will use the value 0.01. + /// Previosly we used 1e-8 but that was causing issues: + /// http://community.sharpdevelop.net/forums/t/16048.aspx + /// + public const double Epsilon = 0.01; + + /// + /// Returns true if the doubles are close (difference smaller than 0.01). + /// + public static bool IsClose(this double d1, double d2) + { + if (d1 == d2) // required for infinities + return true; + return Math.Abs(d1 - d2) < Epsilon; + } + + //// /// + //// /// Returns true if the doubles are close (difference smaller than 0.01). + //// /// + //// public static bool IsClose(this Size d1, Size d2) + //// { + //// return IsClose(d1.Width, d2.Width) && IsClose(d1.Height, d2.Height); + //// } + //// + //// /// + //// /// Returns true if the doubles are close (difference smaller than 0.01). + //// /// + //// public static bool IsClose(this Vector d1, Vector d2) + //// { + //// return IsClose(d1.X, d2.X) && IsClose(d1.Y, d2.Y); + //// } + + /// + /// Forces the value to stay between mininum and maximum. + /// + /// minimum, if value is less than minimum. + /// Maximum, if value is greater than maximum. + /// Otherwise, value. + public static double CoerceValue(this double value, double minimum, double maximum) + { + return Math.Max(Math.Min(value, maximum), minimum); + } + + /// + /// Forces the value to stay between mininum and maximum. + /// + /// minimum, if value is less than minimum. + /// Maximum, if value is greater than maximum. + /// Otherwise, value. + public static int CoerceValue(this int value, int minimum, int maximum) + { + return Math.Max(Math.Min(value, maximum), minimum); + } + #endregion + +//// #region CreateTypeface +//// /// +//// /// Creates typeface from the framework element. +//// /// +//// public static Typeface CreateTypeface(this FrameworkElement fe) +//// { +//// return new Typeface((FontFamily)fe.GetValue(TextBlock.FontFamilyProperty), +//// (FontStyle)fe.GetValue(TextBlock.FontStyleProperty), +//// (FontWeight)fe.GetValue(TextBlock.FontWeightProperty), +//// (FontStretch)fe.GetValue(TextBlock.FontStretchProperty)); +//// } +//// #endregion + + #region AddRange / Sequence + public static void AddRange(this ICollection collection, IEnumerable elements) + { + foreach (T e in elements) + collection.Add(e); + } + + /// + /// Creates an IEnumerable with a single value. + /// + public static IEnumerable Sequence(T value) + { + yield return value; + } + #endregion + + #region XML reading + /// + /// Gets the value of the attribute, or null if the attribute does not exist. + /// + public static string GetAttributeOrNull(this XmlElement element, string attributeName) + { + XmlAttribute attr = element.GetAttributeNode(attributeName); + return attr != null ? attr.Value : null; + } + + /// + /// Gets the value of the attribute as boolean, or null if the attribute does not exist. + /// + public static bool? GetBoolAttribute(this XmlElement element, string attributeName) + { + XmlAttribute attr = element.GetAttributeNode(attributeName); + return attr != null ? (bool?)XmlConvert.ToBoolean(attr.Value) : null; + } + + /// + /// Gets the value of the attribute as boolean, or null if the attribute does not exist. + /// + public static bool? GetBoolAttribute(this XmlReader reader, string attributeName) + { + string attributeValue = reader.GetAttribute(attributeName); + if (attributeValue == null) + return null; + else + return XmlConvert.ToBoolean(attributeValue); + } + #endregion + +//// #region DPI independence +//// public static Rect TransformToDevice(this Rect rect, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; +//// return Rect.Transform(rect, matrix); +//// } +//// +//// public static Rect TransformFromDevice(this Rect rect, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice; +//// return Rect.Transform(rect, matrix); +//// } +//// +//// public static Size TransformToDevice(this Size size, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; +//// return new Size(size.Width * matrix.M11, size.Height * matrix.M22); +//// } +//// +//// public static Size TransformFromDevice(this Size size, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice; +//// return new Size(size.Width * matrix.M11, size.Height * matrix.M22); +//// } +//// +//// public static Point TransformToDevice(this Point point, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice; +//// return new Point(point.X * matrix.M11, point.Y * matrix.M22); +//// } +//// +//// public static Point TransformFromDevice(this Point point, Visual visual) +//// { +//// Matrix matrix = PresentationSource.FromVisual(visual).CompositionTarget.TransformFromDevice; +//// return new Point(point.X * matrix.M11, point.Y * matrix.M22); +//// } +//// #endregion + + #region System.Drawing <-> WPF conversions + //// public static System.Drawing.Point ToSystemDrawing(this Point p) + //// { + //// return new System.Drawing.Point((int)p.X, (int)p.Y); + //// } + //// + //// public static Point ToWpf(this System.Drawing.Point p) + //// { + //// return new Point(p.X, p.Y); + //// } + //// + //// public static Size ToWpf(this System.Drawing.Size s) + //// { + //// return new Size(s.Width, s.Height); + //// } + //// + //// public static Rect ToWpf(this System.Drawing.Rectangle rect) + //// { + //// return new Rect(rect.Location.ToWpf(), rect.Size.ToWpf()); + //// } + #endregion + +//// public static IEnumerable VisualAncestorsAndSelf(this DependencyObject obj) +//// { +//// while (obj != null) +//// { +//// yield return obj; +//// if (obj is Visual || obj is System.Windows.Media.Media3D.Visual3D) +//// { +//// obj = VisualTreeHelper.GetParent(obj); +//// } +//// else if (obj is FrameworkContentElement) +//// { +//// // When called with a non-visual such as a TextElement, walk up the +//// // logical tree instead. +//// obj = ((FrameworkContentElement)obj).Parent; +//// } +//// else +//// { +//// break; +//// } +//// } +//// } +//// +//// [Conditional("DEBUG")] +//// public static void CheckIsFrozen(Freezable f) +//// { +//// if (f != null && !f.IsFrozen) +//// Debug.WriteLine("Performance warning: Not frozen: " + f.ToString()); +//// } + + [Conditional("DEBUG")] + public static void Log(bool condition, string format, params object[] args) + { + if (condition) + { + string output = DateTime.Now.ToString("hh:MM:ss") + ": " + string.Format(format, args) + Environment.NewLine + Environment.StackTrace; + Console.WriteLine(output); + Debug.WriteLine(output); + } + } + } + +} diff --git a/src/HL/Manager/HLTheme.cs b/src/HL/Manager/HLTheme.cs new file mode 100644 index 0000000..e0c4de1 --- /dev/null +++ b/src/HL/Manager/HLTheme.cs @@ -0,0 +1,307 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.HighlightingTheme; + using HL.Resources; + using HL.Xshtd; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.IO; + using System.Linq; + using System.Xml; + + /// + /// Implements a highlighting theme which is based on a WPF theme (eg. 'Light') + /// with a corresponding set of highlighting definitions (eg. 'XML', 'C#' etc) + /// to ensure that highlightings are correct in the contecxt of + /// (different background colors) WPF themes. + /// + internal class HLTheme : IHLTheme + { + #region fields + private readonly object lockObj = new object(); + private Dictionary highlightingsByName = new Dictionary(); + private Dictionary highlightingsByExtension = new Dictionary(StringComparer.OrdinalIgnoreCase); + private List allHighlightings = new List(); + private bool _HLThemeIsInitialized; + + private XhstdThemeDefinition _xshtd; + private XmlHighlightingThemeDefinition _hlTheme; + private readonly IHighlightingThemeDefinitionReferenceResolver _hLThemeResolver; + #endregion fields + + #region ctors + /// + /// Class constructor for GENERIC highlighting definitions. + /// + /// Generic highlighting definitions ar usually defined in xshd + /// files and stand on their own (do not need additional processing/resources + /// to compute highlighting rules and formating information). + /// + /// + /// + /// + public HLTheme(string paramKey, + string paramHLBasePrefix, + string paramDisplayName) + : this() + { + Key = paramKey; + HLBasePrefix = paramHLBasePrefix; // This Highlighting is GENERIC - based on 'itself' + HLBaseKey = paramKey; + + DisplayName = paramDisplayName; + } + + /// + /// Class constructor for derived highlighting themes. + /// + /// Derived highlighting themes have a base highlighting (eg 'Light') + /// and an 'overwritting' highlighting themes definition using an xshTd file resource. + /// + /// + /// + /// + /// + /// + /// + public HLTheme(string paramKey, + string paramHLBaseKey, + string paramDisplayName, + string paramHLThemePrefix, string paramHLThemeName, + IHighlightingThemeDefinitionReferenceResolver themeResolver) + : this() + { + Key = paramKey; + HLBaseKey = paramHLBaseKey; + + HLThemePrefix = paramHLThemePrefix; + HLThemeFileName = paramHLThemeName; + + _hLThemeResolver = themeResolver; + + DisplayName = paramDisplayName; + } + + /// + /// Hidden class constructor + /// + protected HLTheme() + { + } + #endregion ctors + + #region properties + /// + /// Gets the display independent key value that should by unique in an + /// overall collection of highlighting themes and should be used for retrieval purposes. + /// + public string Key { get; } + + /// + /// Gets the prefix of the XSHD resources that should be used to lookup + /// the actual resource for this theme. + /// + /// This property is null for a derived highlighting theme since finding its + /// base highlighting should by performed through + /// and the corresponding property of that entry. + /// + public string HLBasePrefix { get; } + + /// + /// Gets the name of theme (eg. 'Dark' or 'Light' which is used as + /// the base of a derived highlighting theme. + /// + /// This property has the same value as the property + /// if the highlighting is GENERIC (since these highlightings come without + /// additional theme resources). + /// + public string HLBaseKey { get; } + + /// + /// Gets the prefix of the resource under which a theme resource definition + /// file xshTd can be found (eg 'HL.Resources.Themes'). + /// + public string HLThemePrefix { get; } + + /// + /// Gets the file name under which a theme resource definition + /// file xshTd can be found (eg 'Dark.xshtd'). + /// + public string HLThemeFileName { get; } + + /// + /// Gets the name of theme (eg. 'Dark', 'Light' or 'True Blue' for display purposes in the UI. + /// + public string DisplayName { get; } + + /// + /// Gets an (ordered by Name) list copy of all highlightings defined in this object. + /// + public ReadOnlyCollection HighlightingDefinitions + { + get + { + lock (lockObj) + { + return Array.AsReadOnly(allHighlightings.OrderBy(x => x.Name).ToArray()); + } + } + } + + /// + /// Gets the theme highlighting definition for this theme + /// or null (highlighting definition is generic and not based on a theme). + /// + public IHighlightingThemeDefinition HlTheme + { + get + { + ResolveHighLightingTheme(); + + return _hlTheme; + } + } + + /// + /// Gets/sets whether built-in themes have already been registered or not + /// Use this to avoid registration of built-in themes twice for one and the + /// same highlighting theme. + /// + public bool IsBuiltInThemesRegistered { get; set; } + #endregion properties + + #region methods + /// + /// Gets the highlighting definition by name, or null if it is not found. + /// + public IHighlightingDefinition GetDefinition(string name) + { + lock (lockObj) + { + this.ResolveHighLightingTheme(); + + IHighlightingDefinition rh; + if (highlightingsByName.TryGetValue(name, out rh)) + return rh; + else + return null; + } + } + + /// + /// Gets the highlighting theme definition by name, or null if it is not found. + /// + public SyntaxDefinition GetThemeDefinition(string highlightingName) + { + lock (lockObj) + { + this.ResolveHighLightingTheme(); + + return _hlTheme.GetNamedSyntaxDefinition(highlightingName); + } + } + + /// + /// Gets a highlighting definition by extension. + /// Returns null if the definition is not found. + /// + public IHighlightingDefinition GetDefinitionByExtension(string extension) + { + lock (lockObj) + { + this.ResolveHighLightingTheme(); + + IHighlightingDefinition rh; + if (highlightingsByExtension.TryGetValue(extension, out rh)) + return rh; + else + return null; + } + } + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// The highlighting definition. + public void RegisterHighlighting(string name, + string[] extensions, + IHighlightingDefinition highlighting) + { + lock (lockObj) + { + // Perform an update if this highlighting happens to be available already + var itemInList = allHighlightings.FirstOrDefault(i => name == i.Name); + if (itemInList != null) + allHighlightings.Remove(itemInList); + + allHighlightings.Add(highlighting); + if (name != null) + { + highlightingsByName[name] = highlighting; + } + + if (extensions != null) + { + foreach (string ext in extensions) + { + highlightingsByExtension[ext] = highlighting; + } + } + } + } + + /// + /// Loads the highlighting theme for this highlighting definition + /// (if an additional theme was configured) + /// + protected virtual void ResolveHighLightingTheme() + { + if (_hlTheme != null || _HLThemeIsInitialized == true) + return; + + _HLThemeIsInitialized = true; // Initialize this at most once + + // Load the highlighting theme and setup converter to XmlHighlightingThemeDefinition + _xshtd = ResolveHighLightingTheme(HLThemePrefix, HLThemeFileName); + + if (_hLThemeResolver == null || _xshtd == null) + return; + + _hlTheme = new XmlHighlightingThemeDefinition(_xshtd, _hLThemeResolver); + } + + /// + /// Converts a XSHTD reference from namespace prefix and themename + /// into a object and returns it. + /// + /// + /// + /// + public XhstdThemeDefinition ResolveHighLightingTheme(string hLPrefix, string hLThemeName) + { + if (string.IsNullOrEmpty(hLPrefix) || string.IsNullOrEmpty(hLThemeName)) + return null; + + using (Stream s = HLResources.OpenStream(hLPrefix, hLThemeName)) + { + using (XmlTextReader reader = new XmlTextReader(s)) + { + return HighlightingThemeLoader.LoadXshd(reader, false); + } + } + } + #endregion methods + } +} diff --git a/src/HL/Manager/HighlightingBrush.cs b/src/HL/Manager/HighlightingBrush.cs new file mode 100644 index 0000000..90678af --- /dev/null +++ b/src/HL/Manager/HighlightingBrush.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using System; + using System.Diagnostics; + using System.Reflection; + using System.Runtime.Serialization; + using System.Windows; + using System.Windows.Media; + using ICSharpCode.AvalonEdit.Highlighting; + using ICSharpCode.AvalonEdit.Rendering; + + /// + /// HighlightingBrush implementation that finds a brush using a resource. + /// + [Serializable] + sealed class SystemColorHighlightingBrush : HighlightingBrush, ISerializable + { + readonly PropertyInfo property; + + public SystemColorHighlightingBrush(PropertyInfo property) + { + Debug.Assert(property.ReflectedType == typeof(SystemColors)); + Debug.Assert(typeof(Brush).IsAssignableFrom(property.PropertyType)); + this.property = property; + } + + public override Brush GetBrush(ITextRunConstructionContext context) + { + return (Brush)property.GetValue(null, null); + } + + public override string ToString() + { + return property.Name; + } + + SystemColorHighlightingBrush(SerializationInfo info, StreamingContext context) + { + property = typeof(SystemColors).GetProperty(info.GetString("propertyName")); + if (property == null) + throw new ArgumentException("Error deserializing SystemColorHighlightingBrush"); + } + + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("propertyName", property.Name); + } + + public override bool Equals(object obj) + { + SystemColorHighlightingBrush other = obj as SystemColorHighlightingBrush; + if (other == null) + return false; + return object.Equals(this.property, other.property); + } + + public override int GetHashCode() + { + return property.GetHashCode(); + } + } + +} diff --git a/src/HL/Manager/HighlightingLoader.cs b/src/HL/Manager/HighlightingLoader.cs new file mode 100644 index 0000000..b52c2de --- /dev/null +++ b/src/HL/Manager/HighlightingLoader.cs @@ -0,0 +1,145 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.HighlightingTheme; + using ICSharpCode.AvalonEdit.Highlighting; + using ICSharpCode.AvalonEdit.Highlighting.Xshd; + using System; + using System.Xml; + using System.Xml.Schema; + + /// + /// Static class with helper methods to load XSHD highlighting files. + /// + public static class HighlightingLoader + { + #region XSHD loading + /// + /// Lodas a syntax definition from the xml reader. + /// + public static XshdSyntaxDefinition LoadXshd(XmlReader reader) + { + return LoadXshd(reader, false); + } + + internal static XshdSyntaxDefinition LoadXshd(XmlReader reader, bool skipValidation) + { + if (reader == null) + throw new ArgumentNullException("reader"); + try + { + reader.MoveToContent(); + //// if (reader.NamespaceURI == V2Loader.Namespace) + //// { + return V2Loader.LoadDefinition(reader, skipValidation); + //// } + //// else + //// { + //// return V1Loader.LoadDefinition(reader, skipValidation); + //// } + } + catch (XmlSchemaException ex) + { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } + catch (XmlException ex) + { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } + } + + static Exception WrapException(Exception ex, int lineNumber, int linePosition) + { + return new HighlightingDefinitionInvalidException(FormatExceptionMessage(ex.Message, lineNumber, linePosition), ex); + } + + internal static string FormatExceptionMessage(string message, int lineNumber, int linePosition) + { + if (lineNumber <= 0) + return message; + else + return "Error at position (line " + lineNumber + ", column " + linePosition + "):\n" + message; + } + + internal static XmlReader GetValidatingReader(XmlReader input, bool ignoreWhitespace, XmlSchemaSet schemaSet) + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.CloseInput = true; + settings.IgnoreComments = true; + settings.IgnoreWhitespace = ignoreWhitespace; + if (schemaSet != null) + { + settings.Schemas = schemaSet; + settings.ValidationType = ValidationType.Schema; + } + return XmlReader.Create(input, settings); + } + + internal static XmlSchemaSet LoadSchemaSet(XmlReader schemaInput) + { + XmlSchemaSet schemaSet = new XmlSchemaSet(); + schemaSet.Add(null, schemaInput); + schemaSet.ValidationEventHandler += delegate (object sender, ValidationEventArgs args) + { + throw new HighlightingDefinitionInvalidException(args.Message); + }; + return schemaSet; + } + #endregion + + #region Load Highlighting from XSHD + /// + /// Creates a highlighting definition from the XSHD file. + /// + public static IHighlightingDefinition Load(XshdSyntaxDefinition syntaxDefinition, + IHighlightingDefinitionReferenceResolver resolver) + { + if (syntaxDefinition == null) + throw new ArgumentNullException("syntaxDefinition"); + + return new XmlHighlightingDefinition(syntaxDefinition, resolver); + } + + /// + /// Loads a highlighting definition base on a: + /// + /// + /// Themed Highlighting Definition + /// (This contains the color definition for a highlighting in this theme) + /// + /// + /// A Highlighting definition + /// (This contains the pattern matching and color definitions where the later + /// is usually overwritten be a highlighting theme) + /// + /// An object that can resolve a highlighting definition by its name. + /// + public static IHighlightingDefinition Load(SyntaxDefinition themedHighlights, + XshdSyntaxDefinition syntaxDefinition, + IHighlightingDefinitionReferenceResolver resolver + ) + { + if (syntaxDefinition == null) + throw new ArgumentNullException("syntaxDefinition"); + + return new XmlHighlightingDefinition(themedHighlights, syntaxDefinition, resolver); + } + + /// + /// Creates a highlighting definition from the XSHD file that is already initialled + /// in the instance of the parameter. + /// + public static IHighlightingDefinition Load(XmlReader reader, + IHighlightingDefinitionReferenceResolver resolver) + { + return Load(LoadXshd(reader), resolver); + } + #endregion + } +} diff --git a/src/HL/Manager/HighlightingThemeLoader.cs b/src/HL/Manager/HighlightingThemeLoader.cs new file mode 100644 index 0000000..f091b81 --- /dev/null +++ b/src/HL/Manager/HighlightingThemeLoader.cs @@ -0,0 +1,117 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.Xshtd; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Xml; + using System.Xml.Schema; + + /// + /// Static class with helper methods to load XSHTD highlighting files. + /// + static class HighlightingThemeLoader + { + #region XSHD loading + /// + /// Lodas a syntax definition from the xml reader. + /// + public static XhstdThemeDefinition LoadXshd(XmlReader reader) + { + return LoadXshd(reader, false); + } + + internal static XhstdThemeDefinition LoadXshd(XmlReader reader, bool skipValidation) + { + if (reader == null) + throw new ArgumentNullException("reader"); + try + { + reader.MoveToContent(); + if (reader.NamespaceURI == XshtdLoader.Namespace) + { + return XshtdLoader.LoadDefinition(reader, skipValidation); + } + + throw new ArgumentOutOfRangeException(reader.NamespaceURI); + } + catch (XmlSchemaException ex) + { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } + catch (XmlException ex) + { + throw WrapException(ex, ex.LineNumber, ex.LinePosition); + } + } + + static Exception WrapException(Exception ex, int lineNumber, int linePosition) + { + return new HighlightingDefinitionInvalidException(FormatExceptionMessage(ex.Message, lineNumber, linePosition), ex); + } + + internal static string FormatExceptionMessage(string message, int lineNumber, int linePosition) + { + if (lineNumber <= 0) + return message; + else + return "Error at position (line " + lineNumber + ", column " + linePosition + "):\n" + message; + } + + internal static XmlReader GetValidatingReader(XmlReader input, bool ignoreWhitespace, XmlSchemaSet schemaSet) + { + XmlReaderSettings settings = new XmlReaderSettings(); + settings.CloseInput = true; + settings.IgnoreComments = true; + settings.IgnoreWhitespace = ignoreWhitespace; + if (schemaSet != null) + { + settings.Schemas = schemaSet; + settings.ValidationType = ValidationType.Schema; + } + return XmlReader.Create(input, settings); + } + + internal static XmlSchemaSet LoadSchemaSet(XmlReader schemaInput) + { + XmlSchemaSet schemaSet = new XmlSchemaSet(); + schemaSet.Add(null, schemaInput); + schemaSet.ValidationEventHandler += delegate (object sender, ValidationEventArgs args) + { + throw new HighlightingDefinitionInvalidException(args.Message); + }; + return schemaSet; + } + #endregion + + #region Load Highlighting from XSHD + /// + /// Creates a highlighting definition from the XSHD file. + /// + public static IHighlightingThemeDefinition Load(XhstdThemeDefinition syntaxDefinition, + IHighlightingThemeDefinitionReferenceResolver resolver) + { + if (syntaxDefinition == null) + throw new ArgumentNullException("syntaxDefinition"); + + return new XmlHighlightingThemeDefinition(syntaxDefinition, resolver); + } + + /// + /// Creates a highlighting definition from the XSHD file. + /// + public static IHighlightingThemeDefinition Load(XmlReader reader, + IHighlightingThemeDefinitionReferenceResolver resolver) + { + return Load(LoadXshd(reader), resolver); + } + #endregion + } +} diff --git a/src/HL/Manager/ThemedHighlightingManager.cs b/src/HL/Manager/ThemedHighlightingManager.cs new file mode 100644 index 0000000..caaa067 --- /dev/null +++ b/src/HL/Manager/ThemedHighlightingManager.cs @@ -0,0 +1,269 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.HighlightingTheme; + using HL.Interfaces; + using HL.Resources; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + + /// + /// Implements a Highlighting Manager that associates syntax highlighting definitions with file extentions + /// (*.cs -> 'C#') with consideration of the current WPF App theme + /// + /// Extension App Theme SyntaxHighlighter + /// (*.cs + 'Dark') -> 'C#' (with color definitions for 'Dark') + /// + public class ThemedHighlightingManager : IThemedHighlightingManager + { + #region fields + /// + /// Defines the root namespace under which the built-in xshd highlighting + /// resource files can be found + /// (eg all highlighting for 'Light' should be located here). + /// + public const string HL_GENERIC_NAMESPACE_ROOT = "HL.Resources.Light"; + + /// + /// Defines the root namespace under which the built-in additional xshtd highlighting theme + /// resource files can be found + /// (eg 'Dark' and 'TrueBlue' themes should be located here). + /// + public const string HL_THEMES_NAMESPACE_ROOT = "HL.Resources.Themes"; + + private readonly object lockObj = new object(); + private readonly Dictionary _ThemedHighlightings; + #endregion fields + + #region ctors + /// + /// Class constructor + /// + public ThemedHighlightingManager() + { + _ThemedHighlightings = new Dictionary(); + } + #endregion ctors + + #region properties + /// + /// Gets the current highlighting theme (eg 'Light' or 'Dark') that should be used as + /// a base for the syntax highlighting in AvalonEdit. + /// + public IHLTheme CurrentTheme { get; private set; } + + /// + /// Gets the default HighlightingManager instance. + /// The default HighlightingManager comes with built-in highlightings. + /// + public static IThemedHighlightingManager Instance + { + get + { + return DefaultHighlightingManager.Instance; + } + } + #endregion properties + + #region methods + /// + /// Gets the highlighting definition by name, or null if it is not found. + /// + IHighlightingDefinition IHighlightingDefinitionReferenceResolver.GetDefinition(string name) + { + lock (lockObj) + { + if (CurrentTheme != null) + return CurrentTheme.GetDefinition(name); + + return null; + } + } + + /// + /// Gets an (ordered by Name) list copy of all highlightings defined in this object + /// or an empty collection if there is no highlighting definition available. + /// + public ReadOnlyCollection HighlightingDefinitions + { + get + { + lock (lockObj) + { + if (CurrentTheme != null) + return CurrentTheme.HighlightingDefinitions; + + return new ReadOnlyCollection(new List()); + } + } + } + + /// + /// Gets a highlighting definition by extension. + /// Returns null if the definition is not found. + /// + public IHighlightingDefinition GetDefinitionByExtension(string extension) + { + lock (lockObj) + { + IHLTheme theme; + if (_ThemedHighlightings.TryGetValue(CurrentTheme.Key, out theme) == true) + { + return theme.GetDefinitionByExtension(extension); + } + + return null; + } + } + + /// + /// Registers a highlighting definition for the . + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// The highlighting definition. + public void RegisterHighlighting(string name, string[] extensions, IHighlightingDefinition highlighting) + { + if (highlighting == null) + throw new ArgumentNullException("highlighting"); + + lock (lockObj) + { + if (this.CurrentTheme != null) + { + CurrentTheme.RegisterHighlighting(name, extensions, highlighting); + } + } + } + + /// + /// Registers a highlighting definition. + /// + /// The name to register the definition with. + /// The file extensions to register the definition for. + /// A function that loads the highlighting definition. + public void RegisterHighlighting(string name, string[] extensions, Func lazyLoadedHighlighting) + { + if (lazyLoadedHighlighting == null) + throw new ArgumentNullException("lazyLoadedHighlighting"); + + RegisterHighlighting(name, extensions, new DelayLoadedHighlightingDefinition(name, lazyLoadedHighlighting)); + } + + /// + /// Sets the current highlighting based on the name of the given highöighting theme. + /// (eg: WPF APP Theme 'TrueBlue' -> Resolve highlighting 'C#' to 'TrueBlue'->'C#') + /// + /// Throws an if the WPF APP theme is not known. + /// + /// + public void SetCurrentTheme(string themeNameKey) + { + SetCurrentThemeInternal(themeNameKey); + HLResources.RegisterBuiltInHighlightings(DefaultHighlightingManager.Instance, CurrentTheme); + } + + /// + /// Adds another highlighting theme into the current collection of highlighting themes. + /// + /// + /// + public void ThemedHighlightingAdd(string key, IHLTheme theme) + { + lock (lockObj) + { + _ThemedHighlightings.Add(key, theme); + } + } + + /// + /// Removes a highlighting theme from the current collection + /// of highlighting themes. + /// + /// + public void ThemedHighlightingRemove(string removekey) + { + lock (lockObj) + { + _ThemedHighlightings.Remove(removekey); + } + } + + /// + /// Initializes the current default theme available at start-up of application + /// (without registration of highlightings). + /// + /// + protected void SetCurrentThemeInternal(string themeNameKey) + { + CurrentTheme = _ThemedHighlightings[themeNameKey]; + } + + /// + /// Helper method to find the correct namespace of an internal xshd resource + /// based on the name of a (WPF) theme (eg. 'TrueBlue') and an internal + /// constant (eg. 'HL.Resources') + /// + /// + /// + protected virtual string GetPrefix(string themeNameKey) + { + lock (lockObj) + { + IHLTheme theme; + if (_ThemedHighlightings.TryGetValue(themeNameKey, out theme) == true) + { + return theme.HLBasePrefix; + } + } + + return null; + } + + /// + /// Gets the highlighting theme definition by name, or null if there is none to be found. + /// + /// + SyntaxDefinition IHighlightingThemeDefinitionReferenceResolver.GetThemeDefinition(string highlightingName) + { + lock (lockObj) + { + if (CurrentTheme != null) + return CurrentTheme.GetThemeDefinition(highlightingName); + + return null; + } + } + + /// + /// Gets the highlighting theme definition by name of the theme (eg 'Dark2' or 'TrueBlue') + /// and the highlighting, or null if there is none to be found. + /// + /// + /// + SyntaxDefinition IHighlightingThemeDefinitionReferenceResolver.GetThemeDefinition(string hlThemeName, + string highlightingName) + { + lock (lockObj) + { + IHLTheme highlighting; + this._ThemedHighlightings.TryGetValue(hlThemeName, out highlighting); + + if (highlighting != null) + return highlighting.GetThemeDefinition(hlThemeName); + + return null; + } + } + #endregion methods + } +} diff --git a/src/HL/Manager/V2Loader.cs b/src/HL/Manager/V2Loader.cs new file mode 100644 index 0000000..ce635c9 --- /dev/null +++ b/src/HL/Manager/V2Loader.cs @@ -0,0 +1,366 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.Resources; + using ICSharpCode.AvalonEdit.Highlighting; + using ICSharpCode.AvalonEdit.Highlighting.Xshd; + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media; + using System.Xml; + using System.Xml.Schema; + + /// + /// Loads .xshd files, version 2.0. + /// Version 2.0 files are recognized by the namespace. + /// + static class V2Loader + { + public const string Namespace = "http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"; + + static XmlSchemaSet schemaSet; + + static XmlSchemaSet SchemaSet + { + get + { + if (schemaSet == null) + { + schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader( + HLResources.OpenStream("HL.Modes", "ModeV2.xsd"))); + } + return schemaSet; + } + } + + public static XshdSyntaxDefinition LoadDefinition(XmlReader reader, bool skipValidation) + { + reader = HighlightingLoader.GetValidatingReader(reader, true, skipValidation ? null : SchemaSet); + reader.Read(); + return ParseDefinition(reader); + } + + static XshdSyntaxDefinition ParseDefinition(XmlReader reader) + { + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + XshdSyntaxDefinition def = new XshdSyntaxDefinition(); + def.Name = reader.GetAttribute("name"); + string extensions = reader.GetAttribute("extensions"); + if (extensions != null) + def.Extensions.AddRange(extensions.Split(';')); + ParseElements(def.Elements, reader); + Debug.Assert(reader.NodeType == XmlNodeType.EndElement); + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + return def; + } + + static void ParseElements(ICollection c, XmlReader reader) + { + if (reader.IsEmptyElement) + return; + while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) + { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + if (reader.NamespaceURI != Namespace) + { + if (!reader.IsEmptyElement) + reader.Skip(); + continue; + } + switch (reader.Name) + { + case "RuleSet": + c.Add(ParseRuleSet(reader)); + break; + case "Property": + c.Add(ParseProperty(reader)); + break; + case "Color": + c.Add(ParseNamedColor(reader)); + break; + case "Keywords": + c.Add(ParseKeywords(reader)); + break; + case "Span": + c.Add(ParseSpan(reader)); + break; + case "Import": + c.Add(ParseImport(reader)); + break; + case "Rule": + c.Add(ParseRule(reader)); + break; + default: + throw new NotSupportedException("Unknown element " + reader.Name); + } + } + } + + static XshdElement ParseProperty(XmlReader reader) + { + XshdProperty property = new XshdProperty(); + SetPosition(property, reader); + property.Name = reader.GetAttribute("name"); + property.Value = reader.GetAttribute("value"); + return property; + } + + static XshdRuleSet ParseRuleSet(XmlReader reader) + { + XshdRuleSet ruleSet = new XshdRuleSet(); + SetPosition(ruleSet, reader); + ruleSet.Name = reader.GetAttribute("name"); + ruleSet.IgnoreCase = reader.GetBoolAttribute("ignoreCase"); + + CheckElementName(reader, ruleSet.Name); + ParseElements(ruleSet.Elements, reader); + return ruleSet; + } + + static XshdRule ParseRule(XmlReader reader) + { + XshdRule rule = new XshdRule(); + SetPosition(rule, reader); + rule.ColorReference = ParseColorReference(reader); + if (!reader.IsEmptyElement) + { + reader.Read(); + if (reader.NodeType == XmlNodeType.Text) + { + rule.Regex = reader.ReadContentAsString(); + rule.RegexType = XshdRegexType.IgnorePatternWhitespace; + } + } + return rule; + } + + static XshdKeywords ParseKeywords(XmlReader reader) + { + XshdKeywords keywords = new XshdKeywords(); + SetPosition(keywords, reader); + keywords.ColorReference = ParseColorReference(reader); + reader.Read(); + while (reader.NodeType != XmlNodeType.EndElement) + { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + keywords.Words.Add(reader.ReadElementString()); + } + return keywords; + } + + static XshdImport ParseImport(XmlReader reader) + { + XshdImport import = new XshdImport(); + SetPosition(import, reader); + import.RuleSetReference = ParseRuleSetReference(reader); + if (!reader.IsEmptyElement) + reader.Skip(); + return import; + } + + static XshdSpan ParseSpan(XmlReader reader) + { + XshdSpan span = new XshdSpan(); + SetPosition(span, reader); + span.BeginRegex = reader.GetAttribute("begin"); + span.EndRegex = reader.GetAttribute("end"); + span.Multiline = reader.GetBoolAttribute("multiline") ?? false; + span.SpanColorReference = ParseColorReference(reader); + span.RuleSetReference = ParseRuleSetReference(reader); + if (!reader.IsEmptyElement) + { + reader.Read(); + while (reader.NodeType != XmlNodeType.EndElement) + { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + switch (reader.Name) + { + case "Begin": + if (span.BeginRegex != null) + throw Error(reader, "Duplicate Begin regex"); + span.BeginColorReference = ParseColorReference(reader); + span.BeginRegex = reader.ReadElementString(); + span.BeginRegexType = XshdRegexType.IgnorePatternWhitespace; + break; + case "End": + if (span.EndRegex != null) + throw Error(reader, "Duplicate End regex"); + span.EndColorReference = ParseColorReference(reader); + span.EndRegex = reader.ReadElementString(); + span.EndRegexType = XshdRegexType.IgnorePatternWhitespace; + break; + case "RuleSet": + if (span.RuleSetReference.ReferencedElement != null) + throw Error(reader, "Cannot specify both inline RuleSet and RuleSet reference"); + span.RuleSetReference = new XshdReference(ParseRuleSet(reader)); + reader.Read(); + break; + default: + throw new NotSupportedException("Unknown element " + reader.Name); + } + } + } + return span; + } + + static Exception Error(XmlReader reader, string message) + { + return Error(reader as IXmlLineInfo, message); + } + + static Exception Error(IXmlLineInfo lineInfo, string message) + { + if (lineInfo != null) + return new HighlightingDefinitionInvalidException(HighlightingLoader.FormatExceptionMessage(message, lineInfo.LineNumber, lineInfo.LinePosition)); + else + return new HighlightingDefinitionInvalidException(message); + } + + /// + /// Sets the element's position to the XmlReader's position. + /// + static void SetPosition(XshdElement element, XmlReader reader) + { + IXmlLineInfo lineInfo = reader as IXmlLineInfo; + if (lineInfo != null) + { + element.LineNumber = lineInfo.LineNumber; + element.ColumnNumber = lineInfo.LinePosition; + } + } + + static XshdReference ParseRuleSetReference(XmlReader reader) + { + string ruleSet = reader.GetAttribute("ruleSet"); + if (ruleSet != null) + { + // '/' is valid in highlighting definition names, so we need the last occurence + int pos = ruleSet.LastIndexOf('/'); + if (pos >= 0) + { + return new XshdReference(ruleSet.Substring(0, pos), ruleSet.Substring(pos + 1)); + } + else + { + return new XshdReference(null, ruleSet); + } + } + else + { + return new XshdReference(); + } + } + + static void CheckElementName(XmlReader reader, string name) + { + if (name != null) + { + if (name.Length == 0) + throw Error(reader, "The empty string is not a valid name."); + if (name.IndexOf('/') >= 0) + throw Error(reader, "Element names must not contain a slash."); + } + } + + #region ParseColor + static XshdColor ParseNamedColor(XmlReader reader) + { + XshdColor color = ParseColorAttributes(reader); + // check removed: invisible named colors may be useful now that apps can read highlighting data + //if (color.Foreground == null && color.FontWeight == null && color.FontStyle == null) + // throw Error(reader, "A named color must have at least one element."); + color.Name = reader.GetAttribute("name"); + CheckElementName(reader, color.Name); + color.ExampleText = reader.GetAttribute("exampleText"); + return color; + } + + static XshdReference ParseColorReference(XmlReader reader) + { + string color = reader.GetAttribute("color"); + if (color != null) + { + int pos = color.LastIndexOf('/'); + if (pos >= 0) + { + return new XshdReference(color.Substring(0, pos), color.Substring(pos + 1)); + } + else + { + return new XshdReference(null, color); + } + } + else + { + return new XshdReference(ParseColorAttributes(reader)); + } + } + + static XshdColor ParseColorAttributes(XmlReader reader) + { + XshdColor color = new XshdColor(); + SetPosition(color, reader); + IXmlLineInfo position = reader as IXmlLineInfo; + color.Foreground = ParseColor(position, reader.GetAttribute("foreground")); + color.Background = ParseColor(position, reader.GetAttribute("background")); + color.FontWeight = ParseFontWeight(reader.GetAttribute("fontWeight")); + color.FontStyle = ParseFontStyle(reader.GetAttribute("fontStyle")); + color.Underline = reader.GetBoolAttribute("underline"); + return color; + } + + internal readonly static ColorConverter ColorConverter = new ColorConverter(); + internal readonly static FontWeightConverter FontWeightConverter = new FontWeightConverter(); + internal readonly static FontStyleConverter FontStyleConverter = new FontStyleConverter(); + + static HighlightingBrush ParseColor(IXmlLineInfo lineInfo, string color) + { + if (string.IsNullOrEmpty(color)) + return null; + if (color.StartsWith("SystemColors.", StringComparison.Ordinal)) + return GetSystemColorBrush(lineInfo, color); + else + return FixedColorHighlightingBrush((Color?)ColorConverter.ConvertFromInvariantString(color)); + } + + internal static SystemColorHighlightingBrush GetSystemColorBrush(IXmlLineInfo lineInfo, string name) + { + Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal)); + string shortName = name.Substring(13); + var property = typeof(SystemColors).GetProperty(shortName + "Brush"); + if (property == null) + throw Error(lineInfo, "Cannot find '" + name + "'."); + return new SystemColorHighlightingBrush(property); + } + + static HighlightingBrush FixedColorHighlightingBrush(Color? color) + { + if (color == null) + return null; + return new SimpleHighlightingBrush(color.Value); + } + + static FontWeight? ParseFontWeight(string fontWeight) + { + if (string.IsNullOrEmpty(fontWeight)) + return null; + return (FontWeight?)FontWeightConverter.ConvertFromInvariantString(fontWeight); + } + + static FontStyle? ParseFontStyle(string fontStyle) + { + if (string.IsNullOrEmpty(fontStyle)) + return null; + return (FontStyle?)FontStyleConverter.ConvertFromInvariantString(fontStyle); + } + #endregion + } +} diff --git a/src/HL/Manager/XmlHighlightingDefinition.cs b/src/HL/Manager/XmlHighlightingDefinition.cs new file mode 100644 index 0000000..1cede5d --- /dev/null +++ b/src/HL/Manager/XmlHighlightingDefinition.cs @@ -0,0 +1,522 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.HighlightingTheme; + using ICSharpCode.AvalonEdit.Highlighting; + using ICSharpCode.AvalonEdit.Highlighting.Xshd; + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Runtime.Serialization; + using System.Text; + using System.Text.RegularExpressions; + + [Serializable] + sealed class XmlHighlightingDefinition : IHighlightingDefinition + { + public string Name { get; private set; } + + public XmlHighlightingDefinition(XshdSyntaxDefinition xshd, + IHighlightingDefinitionReferenceResolver resolver) + { + InitializeDefinitions(xshd, resolver); + } + + /// + /// Class constructor from highlighting theme definition resolver + /// and highlighting definition (and resolver) + /// + /// + /// + /// + public XmlHighlightingDefinition(SyntaxDefinition themedHighlights, + XshdSyntaxDefinition xshd, + IHighlightingDefinitionReferenceResolver resolver + ) + { + _themedHighlights = themedHighlights; + InitializeDefinitions(xshd, resolver); + } + + #region RegisterNamedElements + sealed class RegisterNamedElementsVisitor : IXshdVisitor + { + XmlHighlightingDefinition def; + internal readonly Dictionary ruleSets + = new Dictionary(); + + public RegisterNamedElementsVisitor(XmlHighlightingDefinition def) + { + this.def = def; + } + + public object VisitRuleSet(XshdRuleSet ruleSet) + { + HighlightingRuleSet hrs = new HighlightingRuleSet(); + ruleSets.Add(ruleSet, hrs); + if (ruleSet.Name != null) + { + if (ruleSet.Name.Length == 0) + throw Error(ruleSet, "Name must not be the empty string"); + if (def.ruleSetDict.ContainsKey(ruleSet.Name)) + throw Error(ruleSet, "Duplicate rule set name '" + ruleSet.Name + "'."); + + def.ruleSetDict.Add(ruleSet.Name, hrs); + } + ruleSet.AcceptElements(this); + return null; + } + + public object VisitColor(XshdColor color) + { + if (color.Name != null) + { + if (color.Name.Length == 0) + throw Error(color, "Name must not be the empty string"); + + if (def.colorDict.ContainsKey(color.Name)) + throw Error(color, "Duplicate color name '" + color.Name + "'."); + + def.colorDict.Add(color.Name, new HighlightingColor()); + } + return null; + } + + public object VisitKeywords(XshdKeywords keywords) + { + return keywords.ColorReference.AcceptVisitor(this); + } + + public object VisitSpan(XshdSpan span) + { + span.BeginColorReference.AcceptVisitor(this); + span.SpanColorReference.AcceptVisitor(this); + span.EndColorReference.AcceptVisitor(this); + return span.RuleSetReference.AcceptVisitor(this); + } + + public object VisitImport(XshdImport import) + { + return import.RuleSetReference.AcceptVisitor(this); + } + + public object VisitRule(XshdRule rule) + { + return rule.ColorReference.AcceptVisitor(this); + } + } + #endregion + + #region TranslateElements + sealed class TranslateElementVisitor : IXshdVisitor + { + readonly XmlHighlightingDefinition def; + readonly Dictionary ruleSetDict; + readonly Dictionary reverseRuleSetDict; + readonly IHighlightingDefinitionReferenceResolver resolver; + HashSet processingStartedRuleSets = new HashSet(); + HashSet processedRuleSets = new HashSet(); + bool ignoreCase; + + public TranslateElementVisitor(XmlHighlightingDefinition def, Dictionary ruleSetDict, IHighlightingDefinitionReferenceResolver resolver) + { + Debug.Assert(def != null); + Debug.Assert(ruleSetDict != null); + this.def = def; + this.ruleSetDict = ruleSetDict; + this.resolver = resolver; + reverseRuleSetDict = new Dictionary(); + foreach (var pair in ruleSetDict) + { + reverseRuleSetDict.Add(pair.Value, pair.Key); + } + } + + public object VisitRuleSet(XshdRuleSet ruleSet) + { + HighlightingRuleSet rs = ruleSetDict[ruleSet]; + if (processedRuleSets.Contains(ruleSet)) + return rs; + if (!processingStartedRuleSets.Add(ruleSet)) + throw Error(ruleSet, "RuleSet cannot be processed because it contains cyclic "); + + bool oldIgnoreCase = ignoreCase; + if (ruleSet.IgnoreCase != null) + ignoreCase = ruleSet.IgnoreCase.Value; + + rs.Name = ruleSet.Name; + + foreach (XshdElement element in ruleSet.Elements) + { + object o = element.AcceptVisitor(this); + HighlightingRuleSet elementRuleSet = o as HighlightingRuleSet; + if (elementRuleSet != null) + { + Merge(rs, elementRuleSet); + } + else + { + HighlightingSpan span = o as HighlightingSpan; + if (span != null) + { + rs.Spans.Add(span); + } + else + { + HighlightingRule elementRule = o as HighlightingRule; + if (elementRule != null) + { + rs.Rules.Add(elementRule); + } + } + } + } + + ignoreCase = oldIgnoreCase; + processedRuleSets.Add(ruleSet); + + return rs; + } + + static void Merge(HighlightingRuleSet target, HighlightingRuleSet source) + { + target.Rules.AddRange(source.Rules); + target.Spans.AddRange(source.Spans); + } + + public object VisitColor(XshdColor color) + { + HighlightingColor c = null; + + if (def._themedHighlights == null) + { + if (color.Name != null) + c = def.colorDict[color.Name]; + else if (color.Foreground == null && color.Background == null && color.Underline == null && color.FontStyle == null && color.FontWeight == null) + return null; + else + c = new HighlightingColor(); + + c.Name = color.Name; + c.Foreground = color.Foreground; + c.Background = color.Background; + c.Underline = color.Underline; + c.FontStyle = color.FontStyle; + c.FontWeight = color.FontWeight; + } + + return c; + } + + public object VisitKeywords(XshdKeywords keywords) + { + if (keywords.Words.Count == 0) + return Error(keywords, "Keyword group must not be empty."); + foreach (string keyword in keywords.Words) + { + if (string.IsNullOrEmpty(keyword)) + throw Error(keywords, "Cannot use empty string as keyword"); + } + StringBuilder keyWordRegex = new StringBuilder(); + // We can use "\b" only where the keyword starts/ends with a letter or digit, otherwise we don't + // highlight correctly. (example: ILAsm-Mode.xshd with ".maxstack" keyword) + if (keywords.Words.All(IsSimpleWord)) + { + keyWordRegex.Append(@"\b(?>"); + // (?> = atomic group + // atomic groups increase matching performance, but we + // must ensure that the keywords are sorted correctly. + // "\b(?>in|int)\b" does not match "int" because the atomic group captures "in". + // To solve this, we are sorting the keywords by descending length. + int i = 0; + foreach (string keyword in keywords.Words.OrderByDescending(w => w.Length)) + { + if (i++ > 0) + keyWordRegex.Append('|'); + keyWordRegex.Append(Regex.Escape(keyword)); + } + keyWordRegex.Append(@")\b"); + } + else + { + keyWordRegex.Append('('); + int i = 0; + foreach (string keyword in keywords.Words) + { + if (i++ > 0) + keyWordRegex.Append('|'); + if (char.IsLetterOrDigit(keyword[0])) + keyWordRegex.Append(@"\b"); + keyWordRegex.Append(Regex.Escape(keyword)); + if (char.IsLetterOrDigit(keyword[keyword.Length - 1])) + keyWordRegex.Append(@"\b"); + } + keyWordRegex.Append(')'); + } + return new HighlightingRule + { + Color = GetColor(keywords, keywords.ColorReference), + Regex = CreateRegex(keywords, keyWordRegex.ToString(), XshdRegexType.Default) + }; + } + + static bool IsSimpleWord(string word) + { + return char.IsLetterOrDigit(word[0]) && char.IsLetterOrDigit(word, word.Length - 1); + } + + Regex CreateRegex(XshdElement position, string regex, XshdRegexType regexType) + { + if (regex == null) + throw Error(position, "Regex missing"); + RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture; + if (regexType == XshdRegexType.IgnorePatternWhitespace) + options |= RegexOptions.IgnorePatternWhitespace; + if (ignoreCase) + options |= RegexOptions.IgnoreCase; + try + { + return new Regex(regex, options); + } + catch (ArgumentException ex) + { + throw Error(position, ex.Message); + } + } + + HighlightingColor GetColor(XshdElement position, XshdReference colorReference) + { + if (colorReference.InlineElement != null) + { + return (HighlightingColor)colorReference.InlineElement.AcceptVisitor(this); + } + else if (colorReference.ReferencedElement != null) + { + IHighlightingDefinition definition = GetDefinition(position, colorReference.ReferencedDefinition); + HighlightingColor color = definition.GetNamedColor(colorReference.ReferencedElement); + if (color == null) + throw Error(position, "Could not find color named '" + colorReference.ReferencedElement + "'."); + return color; + } + else + { + return null; + } + } + + IHighlightingDefinition GetDefinition(XshdElement position, string definitionName) + { + if (definitionName == null) + return def; + if (resolver == null) + throw Error(position, "Resolving references to other syntax definitions is not possible because the IHighlightingDefinitionReferenceResolver is null."); + IHighlightingDefinition d = resolver.GetDefinition(definitionName); + if (d == null) + throw Error(position, "Could not find definition with name '" + definitionName + "'."); + return d; + } + + HighlightingRuleSet GetRuleSet(XshdElement position, XshdReference ruleSetReference) + { + if (ruleSetReference.InlineElement != null) + { + return (HighlightingRuleSet)ruleSetReference.InlineElement.AcceptVisitor(this); + } + else if (ruleSetReference.ReferencedElement != null) + { + IHighlightingDefinition definition = GetDefinition(position, ruleSetReference.ReferencedDefinition); + HighlightingRuleSet ruleSet = definition.GetNamedRuleSet(ruleSetReference.ReferencedElement); + if (ruleSet == null) + throw Error(position, "Could not find rule set named '" + ruleSetReference.ReferencedElement + "'."); + return ruleSet; + } + else + { + return null; + } + } + + public object VisitSpan(XshdSpan span) + { + string endRegex = span.EndRegex; + if (string.IsNullOrEmpty(span.BeginRegex) && string.IsNullOrEmpty(span.EndRegex)) + throw Error(span, "Span has no start/end regex."); + if (!span.Multiline) + { + if (endRegex == null) + endRegex = "$"; + else if (span.EndRegexType == XshdRegexType.IgnorePatternWhitespace) + endRegex = "($|" + endRegex + "\n)"; + else + endRegex = "($|" + endRegex + ")"; + } + HighlightingColor wholeSpanColor = GetColor(span, span.SpanColorReference); + return new HighlightingSpan + { + StartExpression = CreateRegex(span, span.BeginRegex, span.BeginRegexType), + EndExpression = CreateRegex(span, endRegex, span.EndRegexType), + RuleSet = GetRuleSet(span, span.RuleSetReference), + StartColor = GetColor(span, span.BeginColorReference), + SpanColor = wholeSpanColor, + EndColor = GetColor(span, span.EndColorReference), + SpanColorIncludesStart = true, + SpanColorIncludesEnd = true + }; + } + + public object VisitImport(XshdImport import) + { + HighlightingRuleSet hrs = GetRuleSet(import, import.RuleSetReference); + XshdRuleSet inputRuleSet; + if (reverseRuleSetDict.TryGetValue(hrs, out inputRuleSet)) + { + // ensure the ruleset is processed before importing its members + if (VisitRuleSet(inputRuleSet) != hrs) + Debug.Fail("this shouldn't happen"); + } + return hrs; + } + + public object VisitRule(XshdRule rule) + { + return new HighlightingRule + { + Color = GetColor(rule, rule.ColorReference), + Regex = CreateRegex(rule, rule.Regex, rule.RegexType) + }; + } + } + #endregion + + static Exception Error(XshdElement element, string message) + { + if (element.LineNumber > 0) + return new HighlightingDefinitionInvalidException( + "Error at line " + element.LineNumber + ":\n" + message); + else + return new HighlightingDefinitionInvalidException(message); + } + + Dictionary ruleSetDict = new Dictionary(); + Dictionary colorDict = new Dictionary(); + [OptionalField] + Dictionary propDict = new Dictionary(); + + private bool _isThemeInitialized; + + /// + /// Defines highlighting theme information (if any is applicable) for this highlighting. + /// + private readonly SyntaxDefinition _themedHighlights; + + public HighlightingRuleSet MainRuleSet { get; private set; } + + public HighlightingRuleSet GetNamedRuleSet(string name) + { + ApplyTheme(); + + if (string.IsNullOrEmpty(name)) + return MainRuleSet; + + HighlightingRuleSet r; + if (ruleSetDict.TryGetValue(name, out r)) + return r; + else + return null; + } + + public HighlightingColor GetNamedColor(string name) + { + ApplyTheme(); + + HighlightingColor c; + if (colorDict.TryGetValue(name, out c)) + return c; + else + return null; + } + + public IEnumerable NamedHighlightingColors + { + get + { + ApplyTheme(); + + return colorDict.Values; + } + } + + public override string ToString() + { + return this.Name; + } + + public IDictionary Properties + { + get + { + return propDict; + } + } + + private void InitializeDefinitions(XshdSyntaxDefinition xshd, IHighlightingDefinitionReferenceResolver resolver) + { + this.Name = xshd.Name; + + // Create HighlightingRuleSet instances + var rnev = new RegisterNamedElementsVisitor(this); + xshd.AcceptElements(rnev); + + // Assign MainRuleSet so that references can be resolved + foreach (XshdElement element in xshd.Elements) + { + XshdRuleSet xrs = element as XshdRuleSet; + if (xrs != null && xrs.Name == null) + { + if (MainRuleSet != null) + throw Error(element, "Duplicate main RuleSet. There must be only one nameless RuleSet!"); + else + MainRuleSet = rnev.ruleSets[xrs]; + } + } + + if (MainRuleSet == null) + throw new HighlightingDefinitionInvalidException("Could not find main RuleSet."); + + // Translate elements within the rulesets (resolving references and processing imports) + xshd.AcceptElements(new TranslateElementVisitor(this, rnev.ruleSets, resolver)); + + foreach (var p in xshd.Elements.OfType()) + propDict.Add(p.Name, p.Value); + } + + private void ApplyTheme() + { + if (_themedHighlights == null || _isThemeInitialized) + return; + + _isThemeInitialized = true; + + // Replace matching colors in highlightingdefinition with colors from theme sytaxdefinition. + var items = colorDict.ToArray(); + for (int i = 0; i < items.Length; i++) + { + HighlightingColor newColor = _themedHighlights.ColorGet(items[i].Key); + + if (newColor != null) + { + string key = items[i].Key; + colorDict.Remove(key); + colorDict.Add(key, newColor); + } + } + } + } +} diff --git a/src/HL/Manager/XshtdLoader.cs b/src/HL/Manager/XshtdLoader.cs new file mode 100644 index 0000000..66356b0 --- /dev/null +++ b/src/HL/Manager/XshtdLoader.cs @@ -0,0 +1,303 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Manager +{ + using HL.Resources; + using HL.Xshtd; + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media; + using System.Xml; + using System.Xml.Schema; + + /// + /// Loads .xshd files, version 2.0. + /// Version 2.0 files are recognized by the namespace. + /// + static class XshtdLoader + { + public const string Namespace = "http://icsharpcode.net/sharpdevelop/themesyntaxdefinition/2019"; + + static XmlSchemaSet schemaSet; + + static XmlSchemaSet SchemaSet + { + get + { + if (schemaSet == null) + { + schemaSet = HighlightingLoader.LoadSchemaSet(new XmlTextReader( + HLResources.OpenStream("HL.Modes", "ModeV2_htd.xsd"))); + } + return schemaSet; + } + } + + public static XhstdThemeDefinition LoadDefinition(XmlReader reader, bool skipValidation) + { + reader = HighlightingLoader.GetValidatingReader(reader, true, skipValidation ? null : SchemaSet); + reader.Read(); + return ParseDefinition(reader); + } + + static XhstdThemeDefinition ParseDefinition(XmlReader reader) + { + Debug.Assert(reader.LocalName == "ThemeSyntaxDefinition"); + XhstdThemeDefinition def = new XhstdThemeDefinition(); + + def.Name = reader.GetAttribute("name"); + + Stack xmlPath = new Stack(); + xmlPath.Push(def); + + ParseElements(def.Elements, reader, xmlPath); + + var def1 = xmlPath.Pop(); + + Debug.Assert(object.Equals(def, def1)); + Debug.Assert(reader.NodeType == XmlNodeType.EndElement); + Debug.Assert(reader.LocalName == "ThemeSyntaxDefinition"); + + return def; + } + + static void ParseElements(ICollection c, + XmlReader reader, + Stack xmlPath) + { + if (reader.IsEmptyElement) + return; + + while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) + { + Debug.Assert(reader.NodeType == XmlNodeType.Element); + if (reader.NamespaceURI != Namespace) + { + if (!reader.IsEmptyElement) + reader.Skip(); + continue; + } + + switch (reader.Name) + { + case "SyntaxDefinition": + c.Add(ParseSyntaxDefinition(reader, xmlPath)); + break; + + case "Color": + var parent = xmlPath.Peek() as XshtdSyntaxDefinition; + if (parent == null) + throw new Exception("Syntax Error: Color cannot occurr outside of SyntaxDefinition"); + + c.Add(ParseNamedColor(reader, parent)); + break; + + case "GlobalStyles": + ParseGlobalStyles(reader, xmlPath); + break; + + case "DefaultStyle": + case "CurrentLineBackground": + case "LineNumbersForeground": + case "Selection": + case "NonPrintableCharacter": + case "Hyperlink": + ParseGlobalStyle(reader, xmlPath); + break; + + default: + throw new NotSupportedException("Unknown element " + reader.Name); + } + } + } + + static XshtdSyntaxDefinition ParseSyntaxDefinition(XmlReader reader, + Stack xmlPath) + { + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + XshtdSyntaxDefinition def = new XshtdSyntaxDefinition(); + + def.Name = reader.GetAttribute("name"); + string extensions = reader.GetAttribute("extensions"); + + if (extensions != null) + def.Extensions.AddRange(extensions.Split(';')); + + xmlPath.Push(def); + ParseElements(def.Elements, reader, xmlPath); + + def = xmlPath.Pop() as XshtdSyntaxDefinition; + + Debug.Assert(def != null); + Debug.Assert(reader.NodeType == XmlNodeType.EndElement); + Debug.Assert(reader.LocalName == "SyntaxDefinition"); + + return def; + } + + private static XshtdElement ParseGlobalStyles(XmlReader reader, Stack xmlPath) + { + Debug.Assert(reader.LocalName == "GlobalStyles"); + + var def = xmlPath.Peek() as XhstdThemeDefinition; + Debug.Assert(def != null); + + xmlPath.Push(def.GlobalStyleElements); + ParseElements(null, reader, xmlPath); + var def2 = xmlPath.Pop(); + + Debug.Assert(object.Equals(def.GlobalStyleElements, def2)); + Debug.Assert(reader.NodeType == XmlNodeType.EndElement); + Debug.Assert(reader.LocalName == "GlobalStyles"); + + return null; + } + + private static XshtdElement ParseGlobalStyle(XmlReader reader, Stack xmlPath) + { + var def = xmlPath.Peek() as XshtdGlobalStyles; + Debug.Assert(def != null); + + var style = new XshtdGlobalStyle(def); + + style.TypeName = reader.Name; + + string color; + color = reader.GetAttribute("background"); + if (string.IsNullOrEmpty(color) == false) + style.background = (Color?)ColorConverter.ConvertFromInvariantString(color); + + color = reader.GetAttribute("foreground"); + if (string.IsNullOrEmpty(color) == false) + style.foreground = (Color?)ColorConverter.ConvertFromInvariantString(color); + + color = reader.GetAttribute("bordercolor"); + if (string.IsNullOrEmpty(color) == false) + style.bordercolor = (Color?)ColorConverter.ConvertFromInvariantString(color); + + def.Elements.Add(style); + + return def; + } + + static Exception Error(XmlReader reader, string message) + { + return Error(reader as IXmlLineInfo, message); + } + + static Exception Error(IXmlLineInfo lineInfo, string message) + { + if (lineInfo != null) + return new HighlightingDefinitionInvalidException(HighlightingLoader.FormatExceptionMessage(message, lineInfo.LineNumber, lineInfo.LinePosition)); + else + return new HighlightingDefinitionInvalidException(message); + } + + /// + /// Sets the element's position to the XmlReader's position. + /// + static void SetPosition(XshtdElement element, XmlReader reader) + { + IXmlLineInfo lineInfo = reader as IXmlLineInfo; + if (lineInfo != null) + { + element.LineNumber = lineInfo.LineNumber; + element.ColumnNumber = lineInfo.LinePosition; + } + } + + static void CheckElementName(XmlReader reader, string name) + { + if (name != null) + { + if (name.Length == 0) + throw Error(reader, "The empty string is not a valid name."); + if (name.IndexOf('/') >= 0) + throw Error(reader, "Element names must not contain a slash."); + } + } + + #region ParseColor + static XshtdColor ParseNamedColor(XmlReader reader, XshtdSyntaxDefinition syntax) + { + XshtdColor color = ParseColorAttributes(reader, syntax); + // check removed: invisible named colors may be useful now that apps can read highlighting data + //if (color.Foreground == null && color.FontWeight == null && color.FontStyle == null) + // throw Error(reader, "A named color must have at least one element."); + color.Name = reader.GetAttribute("name"); + CheckElementName(reader, color.Name); + color.ExampleText = reader.GetAttribute("exampleText"); + return color; + } + + static XshtdColor ParseColorAttributes(XmlReader reader, XshtdSyntaxDefinition syntax) + { + XshtdColor color = new XshtdColor(syntax); + SetPosition(color, reader); + + IXmlLineInfo position = reader as IXmlLineInfo; + + color.Foreground = ParseColor(position, reader.GetAttribute("foreground")); + color.Background = ParseColor(position, reader.GetAttribute("background")); + color.FontWeight = ParseFontWeight(reader.GetAttribute("fontWeight")); + color.FontStyle = ParseFontStyle(reader.GetAttribute("fontStyle")); + color.Underline = reader.GetBoolAttribute("underline"); + + return color; + } + + internal readonly static ColorConverter ColorConverter = new ColorConverter(); + internal readonly static FontWeightConverter FontWeightConverter = new FontWeightConverter(); + internal readonly static FontStyleConverter FontStyleConverter = new FontStyleConverter(); + + static HighlightingBrush ParseColor(IXmlLineInfo lineInfo, string color) + { + if (string.IsNullOrEmpty(color)) + return null; + if (color.StartsWith("SystemColors.", StringComparison.Ordinal)) + return GetSystemColorBrush(lineInfo, color); + else + return FixedColorHighlightingBrush((Color?)ColorConverter.ConvertFromInvariantString(color)); + } + + internal static SystemColorHighlightingBrush GetSystemColorBrush(IXmlLineInfo lineInfo, string name) + { + Debug.Assert(name.StartsWith("SystemColors.", StringComparison.Ordinal)); + string shortName = name.Substring(13); + var property = typeof(SystemColors).GetProperty(shortName + "Brush"); + if (property == null) + throw Error(lineInfo, "Cannot find '" + name + "'."); + return new SystemColorHighlightingBrush(property); + } + + static HighlightingBrush FixedColorHighlightingBrush(Color? color) + { + if (color == null) + return null; + return new SimpleHighlightingBrush(color.Value); + } + + static FontWeight? ParseFontWeight(string fontWeight) + { + if (string.IsNullOrEmpty(fontWeight)) + return null; + return (FontWeight?)FontWeightConverter.ConvertFromInvariantString(fontWeight); + } + + static FontStyle? ParseFontStyle(string fontStyle) + { + if (string.IsNullOrEmpty(fontStyle)) + return null; + return (FontStyle?)FontStyleConverter.ConvertFromInvariantString(fontStyle); + } + #endregion + } +} diff --git a/src/HL/Modes/ModeV1.xsd b/src/HL/Modes/ModeV1.xsd new file mode 100644 index 0000000..898f1c1 --- /dev/null +++ b/src/HL/Modes/ModeV1.xsd @@ -0,0 +1,296 @@ + + + + + This schema defines the syntax for mode definitions in SharpDevelop. + The schema can be simplified quite a bit but it does the job as is. + + + If you are using this file as a reference it is probably easiest to scroll to + the botton to find the definition of the root element called SyntaxDefinition and + then unwind the different type definitions and refernces. + + Note on coloring: + Many tags define how some symbol should be colored. If a specific symbol + can not be matched onto either a Span definition, Keyword, or a Digit/Number it + will be rendered in the current default color. Which is the default color of the + current span or the default color of the mode as a whole if no span has been entered. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HL/Modes/ModeV2.xsd b/src/HL/Modes/ModeV2.xsd new file mode 100644 index 0000000..df33eba --- /dev/null +++ b/src/HL/Modes/ModeV2.xsd @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HL/Modes/ModeV2_htd.xsd b/src/HL/Modes/ModeV2_htd.xsd new file mode 100644 index 0000000..0b6dd59 --- /dev/null +++ b/src/HL/Modes/ModeV2_htd.xsd @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HL/Resources/HLResources.cs b/src/HL/Resources/HLResources.cs new file mode 100644 index 0000000..059de05 --- /dev/null +++ b/src/HL/Resources/HLResources.cs @@ -0,0 +1,99 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Resources +{ + using System.IO; + using HL.Manager; + + internal class HLResources + { + /// + /// Open a object to an internal resource (eg: xshd file) + /// to load its contents from an 'Embedded Resource'. + /// + /// + /// + /// + public static Stream OpenStream(string prefix, string name) + { + string fileRef = prefix + "." + name; + + Stream s = typeof(HLResources).Assembly.GetManifestResourceStream(fileRef); + if (s == null) + throw new FileNotFoundException("The resource file '" + fileRef + "' was not found."); + + return s; + } + + /// + /// Registers the built-in highlighting definitions on first time request for a definition + /// or when the application changes its WPF Theme (eg. from 'Light' to 'Dark') to load the + /// appropriate highlighting resource when queried for it. + /// + /// + /// + internal static void RegisterBuiltInHighlightings( + DefaultHighlightingManager hlm, + IHLTheme theme) + { + // This registration was already performed for this highlighting theme + if (theme.IsBuiltInThemesRegistered == true) + return; + + hlm.RegisterHighlighting(theme, "XmlDoc", null, "XmlDoc.xshd"); + + hlm.RegisterHighlighting(theme, "C#", new[] { ".cs" }, "CSharp-Mode.xshd"); + hlm.RegisterHighlighting(theme, "Gcode", new[] { ".nc" }, "Gcode.xshd"); + + hlm.RegisterHighlighting(theme, "GRazor", new[] { ".grazor" }, "GRazor-Mode.xshd"); + + + hlm.RegisterHighlighting(theme, "JavaScript", new[] { ".js" }, "JavaScript-Mode.xshd"); + hlm.RegisterHighlighting(theme, "HTML", new[] { ".htm", ".html" }, "HTML-Mode.xshd"); + hlm.RegisterHighlighting(theme, "ASP/XHTML", new[] { ".asp", ".aspx", ".asax", ".asmx", ".ascx", ".master" }, "ASPX.xshd"); + + hlm.RegisterHighlighting(theme, "Boo", new[] { ".boo" }, "Boo.xshd"); + hlm.RegisterHighlighting(theme, "Coco", new[] { ".atg" }, "Coco-Mode.xshd"); + hlm.RegisterHighlighting(theme, "CSS", new[] { ".css" }, "CSS-Mode.xshd"); + hlm.RegisterHighlighting(theme, "C++", new[] { ".c", ".h", ".cc", ".cpp", ".hpp" }, "CPP-Mode.xshd"); + hlm.RegisterHighlighting(theme, "Java", new[] { ".java" }, "Java-Mode.xshd"); + hlm.RegisterHighlighting(theme, "Patch", new[] { ".patch", ".diff" }, "Patch-Mode.xshd"); + hlm.RegisterHighlighting(theme, "PowerShell", new[] { ".ps1", ".psm1", ".psd1" }, "PowerShell.xshd"); + hlm.RegisterHighlighting(theme, "PHP", new[] { ".php" }, "PHP-Mode.xshd"); + hlm.RegisterHighlighting(theme, "Python", new[] { ".py", ".pyw" }, "Python-Mode.xshd"); + hlm.RegisterHighlighting(theme, "TeX", new[] { ".tex" }, "Tex-Mode.xshd"); + hlm.RegisterHighlighting(theme, "TSQL", new[] { ".sql" }, "TSQL-Mode.xshd"); + hlm.RegisterHighlighting(theme, "VB", new[] { ".vb" }, "VB-Mode.xshd"); + hlm.RegisterHighlighting(theme, "XML", (".xml;.xsl;.xslt;.xsd;.manifest;.config;.addin;" + + ".xshd;.wxs;.wxi;.wxl;.proj;.csproj;.vbproj;.ilproj;" + + ".booproj;.build;.xfrm;.targets;.xaml;.xpt;" + + ".xft;.map;.wsdl;.disco;.ps1xml;.nuspec").Split(';'), + "XML-Mode.xshd"); + + hlm.RegisterHighlighting(theme, "MarkDown", new[] { ".md" }, "MarkDown-Mode.xshd"); + + // Additional Highlightings + + hlm.RegisterHighlighting(theme, "ActionScript3", new[] { ".as" }, "AS3.xshd"); + hlm.RegisterHighlighting(theme, "BAT", new[] { ".bat", ".dos" }, "DOSBATCH.xshd"); + hlm.RegisterHighlighting(theme, "F#", new[] { ".fs" }, "FSharp-Mode.xshd"); + hlm.RegisterHighlighting(theme, "HLSL", new[] { ".fx" }, "HLSL.xshd"); + hlm.RegisterHighlighting(theme, "INI", new[] { ".cfg", ".conf", ".ini", ".iss" }, "INI.xshd"); + hlm.RegisterHighlighting(theme, "LOG", new[] { ".log" }, "Log.xshd"); + hlm.RegisterHighlighting(theme, "Pascal", new[] { ".pas" }, "Pascal.xshd"); + hlm.RegisterHighlighting(theme, "PLSQL", new[] { ".plsql" }, "PLSQL.xshd"); + hlm.RegisterHighlighting(theme, "Ruby", new[] { ".rb" }, "Ruby.xshd"); + hlm.RegisterHighlighting(theme, "Scheme", new[] { ".sls", ".sps", ".ss", ".scm" }, "scheme.xshd"); + hlm.RegisterHighlighting(theme, "Squirrel", new[] { ".nut" }, "squirrel.xshd"); + hlm.RegisterHighlighting(theme, "TXT", new[] { ".txt" }, "TXT.xshd"); + hlm.RegisterHighlighting(theme, "VTL", new[] { ".vtl", ".vm" }, "vtl.xshd"); + + theme.IsBuiltInThemesRegistered = true; + } + } +} diff --git a/src/HL/Resources/Light/AS3.xshd b/src/HL/Resources/Light/AS3.xshd new file mode 100644 index 0000000..da04c9c --- /dev/null +++ b/src/HL/Resources/Light/AS3.xshd @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + /// + + + + + + + + // + + + + /\* + \*/ + + + + " + " + + + + + + + + null + Infinity + NaN + undefined + true + false + dynamic + private + public + static + intrinsic + internal + native + override + protected + AS3 + final + void + arguments + Array + Boolean + Class + int + Math + Namespace + Number + Object + RegExp + uint + XML + Bitmap + BitmapData + DisplayObject + DisplayObjectContainer + MovieClip + Shape + Sprite + Stage + ColorTransform + Matrix + Point + Rectangle + Transform + Sound + Video + TextField + ContextMenu + Keyboard + Mouse + ByteArray + Dictionary + Endian + Proxy + Timer + + + + class + extends + implements + import + interface + new + case + do + while + else + if + for + in + switch + throw + get + set + function + var + try + catch + finally + while + with + default + break + continue + delete + return + each + const + namespace + package + include + use + is + as + instanceof + typeof + void + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | \b + ( \d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + diff --git a/src/HL/Resources/Light/ASPX.xshd b/src/HL/Resources/Light/ASPX.xshd new file mode 100644 index 0000000..ebae9b8 --- /dev/null +++ b/src/HL/Resources/Light/ASPX.xshd @@ -0,0 +1,16 @@ + + + + + + + + <% + %> + + + + + + + diff --git a/src/HL/Resources/Light/Boo.xshd b/src/HL/Resources/Light/Boo.xshd new file mode 100644 index 0000000..74a9124 --- /dev/null +++ b/src/HL/Resources/Light/Boo.xshd @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + """ + """ + + + \# + + + // + + + /\* + \*/ + + + + " + " + + + + + \$\{ + } + + + + + ' + ' + + + + + + @/ + / + + + + /\S+/ + + + + self + super + + + is + isa + and + or + not + + + else + elif + if + match + case + unless + otherwise + for + in + while + + + break + continue + return + yield + goto + + + try + raise + ensure + except + retry + success + + + fixed + unsafe + + + bool + double + single + byte + sbyte + short + ushort + int + uint + long + ulong + date + timespan + decimal + char + object + duck + string + regex + + + void + + + cast + as + + + override + static + virtual + abstract + final + transient + partial + + + public + protected + private + internal + + + namespace + import + from + + + get + set + + + null + value + true + false + ast + + + using + unchecked + checked + lock + getter + required + rawArrayIndexing + normalArrayIndexing + yieldAll + + + assert + array + matrix + print + gets + prompt + enumerate + zip + filter + map + cat + __eval__ + __switch__ + + + constructor + destructor + def + include + event + ref + + + pass + + + enum + class + struct + interface + mixin + callable + do + of + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + + /\* + \*/ + + + /\* + \*/ + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/CPP-Mode.xshd b/src/HL/Resources/Light/CPP-Mode.xshd new file mode 100644 index 0000000..f552ad4 --- /dev/null +++ b/src/HL/Resources/Light/CPP-Mode.xshd @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + [?,.;()\[\]{}+\-/%*<>^=~!&]+ + + + __abstract + __box + __delegate + __gc + __identifier + __nogc + __pin + __property + __sealed + __try_cast + __typeof + __value + __event + __hook + __raise + __unhook + __interface + ref class + ref struct + value class + value struct + interface class + interface struct + enum class + enum struct + delegate + event + property + abstract + override + sealed + generic + where + finally + for each + gcnew + in + initonly + literal + nullptr + + + this + + + and + and_eq + bitand + bitor + new + not + not_eq + or + or_eq + xor + xor_eq + + + using + namespace + + + friend + + + private + protected + public + const + volatile + static + + + bool + char + unsigned + union + virtual + double + float + short + signed + void + class + enum + struct + + + false + true + + + do + for + while + + + break + continue + goto + return + + + catch + throw + try + + + case + else + if + switch + default + + + asm + auto + compl + mutable + const_cast + delete + dynamic_cast + explicit + export + extern + inline + int + long + operator + register + reinterpret_cast + sizeof + static_cast + template + typedef + typeid + typename + + + \# + + + // + + + /\* + \*/ + + + " + " + + + + + + ' + ' + + + + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/CSS-Mode.xshd b/src/HL/Resources/Light/CSS-Mode.xshd new file mode 100644 index 0000000..198f6e1 --- /dev/null +++ b/src/HL/Resources/Light/CSS-Mode.xshd @@ -0,0 +1,56 @@ + + + + + + + + + + + + /\* + \*/ + + + \{ + \} + + + \# + \s + + [\d\w] + + + + + /\* + \*/ + + + \: + \;|(?=\}) + + + " + " + + + + + + ' + ' + + + + + + + + + diff --git a/src/HL/Resources/Light/CSharp-Mode.xshd b/src/HL/Resources/Light/CSharp-Mode.xshd new file mode 100644 index 0000000..02bf2b5 --- /dev/null +++ b/src/HL/Resources/Light/CSharp-Mode.xshd @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + \# + + + + (define|undef|if|elif|else|endif|line)\b + + + + // + + + + + + (region|endregion|error|warning|pragma)\b + + + + + + + ///(?!/) + + + + + + + + // + + + + /\* + \*/ + + + + " + " + + + + + + + + ' + ' + + + + + + + + @" + " + + + + + + + + \$" + " + + + + + + + + + + + + @[\w\d_]+ + + + + this + base + + + + as + is + new + sizeof + typeof + stackalloc + + + + true + false + + + + else + if + switch + case + default + do + for + foreach + in + while + lock + + + + break + continue + goto + return + + + + yield + partial + global + where + select + group + by + into + from + ascending + descending + orderby + let + join + on + equals + var + dynamic + await + + + + try + throw + catch + finally + + + + checked + unchecked + + + + fixed + unsafe + + + + bool + byte + char + decimal + double + enum + float + int + long + sbyte + short + struct + uint + ushort + ulong + + + + class + interface + delegate + object + string + void + + + + explicit + implicit + operator + + + + params + ref + out + + + + abstract + const + event + extern + override + readonly + sealed + static + virtual + volatile + async + + + + public + protected + private + internal + + + + namespace + using + + + + get + set + add + remove + + + + null + value + + + + nameof + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + diff --git a/src/HL/Resources/Light/Coco-Mode.xshd b/src/HL/Resources/Light/Coco-Mode.xshd new file mode 100644 index 0000000..47ea530 --- /dev/null +++ b/src/HL/Resources/Light/Coco-Mode.xshd @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + [{}\(\)\[\]|+\-=\.]+ + + + ANY + CHARACTERS + COMMENTS + COMPILER + CONTEXT + END + FROM + IF + IGNORE + NAMESPACE + NESTED + PRAGMAS + PRODUCTIONS + SYNC + TO + TOKENS + TOKENNAMES + WEAK + using + + + // + + + /\* + \*/ + + + COMPILER + TOKENNAMES + + + " + " + + + ' + ' + + + < + > + + + \(\. + \.\) + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/DOSBATCH.xshd b/src/HL/Resources/Light/DOSBATCH.xshd new file mode 100644 index 0000000..71a97bd --- /dev/null +++ b/src/HL/Resources/Light/DOSBATCH.xshd @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + %[0-9] + %[A-Z]+% + + + + [-/][A-Z]+ + + + + %[0-9] + %[A-Z]+% + + + + + + + + [?,;()\[\]{}+\-/%*<>^+~!|&]+ + + + [G][O][T][O]+[ ]+[A-Z]+ + + ^:[A-Z]+ + + + % + % + + + + [ ?,.;()\[\]{}+\-/%*<>^+~!|&]+[0-9]+[ ?,.;()\[\]{}+\-/%*<>^+~!|&]+\n + + + + + ^@[A-Z]+ + + + (ECHO\.) + + + ASSOC + AT + ATTRIB + BREAK + CACLS + CALL + CD + CHCP + CHDIR + CHKDSK + CLS + CMD + COLOR + COMP + COMPACT + CONVERT + COPY + DATE + DEL + DIR + DISKCOMP + DISKCOPY + DOSKEY + ECHO + + ENABLEEXTENSIONS + ENDLOCAL + ERASE + EXIT + FC + FIND + FINDSTR + FOR + FORMAT + FTYPE + + GRAFTABL + HELP + IF + KEYB + LABEL + MD + MKDIR + MODE + MORE + MOVE + NET + PATH + PAUSE + POPD + PRINT + PROMPT + PUSHD + RD + RECOVER + + REN + RENAME + REPLACE + RESTORE + RMDIR + SET + SETLOCAL + SHIFT + SORT + START + SUBST + TIME + TITLE + TREE + TYPE + VER + VERIFY + VOL + XCOPY + + + + DO + IN + NOT + ERRORLEVEL + EXIST + EQU + NEQ + LSS + LEQ + GTR + GEQ + CMDEXTVERSION + DEFINED + CON + COM + MIN + MAX + SEPARATE + SHARED + LOW + NORMAL + HIGH + REALTIME + WAIT + OTHER + nul + + + + EOL + SKIP + DELIMS + TOKENS + ON + OFF + USE + + + + == + EQU + NEQ + LSS + LEQ + GTR + GEQ + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/FSharp-Mode.xshd b/src/HL/Resources/Light/FSharp-Mode.xshd new file mode 100644 index 0000000..1c085ad --- /dev/null +++ b/src/HL/Resources/Light/FSharp-Mode.xshd @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + \# + + + + (define|undef|if|elif|else|endif|line)\b + + + + // + + + + + + (region|endregion|error|warning|pragma)\b + + + + + + + /// + + + + + + + + + // + + + + + \(\* + \*\) + + + + + " + " + + + + + + + + ' + ' + + + + + + + + + @" + " + + + + + + + + + @[\w\d_]+ + + + + and + as + assert + begin + default + do + done + downcast + downto + else + enum + exception + extern + false + finally + for + fun + function + if + in + inherit + land + lazy + let + match + module + mutable + new + of + open + or + rec + sig + struct + then + to + true + try + type + val + when + inline + upcast + while + + + atomic + break + checked + component + const + constraint + constructor + continue + decimal + eager + event + external + fixed + functor + include + method + mixin + process + property + pure + readonly + return + sealed + + + + class + end + interface + delegate + object + string + + + + abstract + member + with + + + + override + + + static + virtual + volatile + async + + + + public + protected + private + internal + + + + + namespace + using + + + + get + set + add + remove + + + + null + + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + diff --git a/src/HL/Resources/Light/GRazor-Mode.xshd b/src/HL/Resources/Light/GRazor-Mode.xshd new file mode 100644 index 0000000..0484999 --- /dev/null +++ b/src/HL/Resources/Light/GRazor-Mode.xshd @@ -0,0 +1,423 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \@\* + \*\@ + + + + + \@\{ + \} + + + + + \@\( + \) + + + + + \@functions\s*\{ + \} + + + + + \@for + \} + + + + + \@if + \} + + + + + \@foreach + \} + + + + + \@while + \} + + + + + + @@ + + + + \@ + \)|\< + + + + + + (?<=@for)\s*\( + \) + + + @: + $ + + + + + + (?<=@foreach)\s*\( + \) + + + @: + $ + + + + + + (?<=@if)\s*\( + \) + + + @: + $ + + + + + + (?<=@while)\s*\( + \) + + + @: + $ + + + + + + . + + + + + & + [\w\d\#]+ + ; + + + + & + [\w\d\#]* + #missing ; + + + + + + @@ + + + + \@\* + \*\@ + + + @ + + + \{ + \} + + + + \( + \) + + + + + + " + " + + + + + + + + ' + ' + + + + + + + + this + base + + + + as + is + new + sizeof + typeof + stackalloc + + + + true + false + + + + else + if + switch + case + default + do + for + foreach + in + while + lock + + + + break + continue + goto + return + + + + yield + partial + global + where + select + group + by + into + from + ascending + descending + orderby + let + join + on + equals + var + dynamic + + + + try + throw + catch + finally + + + + checked + unchecked + + + + fixed + unsafe + + + + bool + byte + char + decimal + double + enum + float + int + long + sbyte + short + struct + uint + ushort + ulong + + + + class + interface + delegate + object + string + void + + + + explicit + implicit + operator + + + + params + ref + out + + + + abstract + const + event + extern + override + readonly + sealed + static + virtual + volatile + + + + public + protected + private + internal + + + + namespace + using + + + + get + set + add + remove + + + + null + value + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + + + + + + + \{ + \} + + + \( + \) + + + + + + + \{ + \} + + + \( + \) + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/Gcode.xshd b/src/HL/Resources/Light/Gcode.xshd new file mode 100644 index 0000000..d21e238 --- /dev/null +++ b/src/HL/Resources/Light/Gcode.xshd @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + N([0-9.-]) + (?![0-9.-]) + + + N + + + G([0-9.-]) + (?![0-9.-]) + + + G + + + X([0-9.-]) + (?![0-9.-]) + + + X + + + Y([0-9.-]) + (?![0-9.-]) + + + Y + + + Z([0-9.-]) + (?![0-9.-]) + + + Z + + + M([0-9.-]) + (?![0-9.-]) + + + M + + + S([0-9.-]) + (?![0-9.-]) + + + S + + + I([0-9.-]) + (?![0-9.-]) + + + I + + + J([0-9.-]) + (?![0-9.-]) + + + J + + + K([0-9.-]) + (?![0-9.-]) + + + K + + + %([0-9.-]) + (?![0-9.-]) + + + % + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/HLSL.xshd b/src/HL/Resources/Light/HLSL.xshd new file mode 100644 index 0000000..306bb1a --- /dev/null +++ b/src/HL/Resources/Light/HLSL.xshd @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + [?,.;:()\[\]{}+\-/%*<>^!|]+ + + + + + + + + + (if + |else + |break + |continue + |do + |for + |switch + |while + |return + |technique + |pass + |compile + |sampler + |register + |typedef + |struct + |auto|catch|char|class|const_cast + |default|delete|dynamic_cast + |enum|explicit|friend|goto + |long|mutable|new|operator + |private|protected|public + |reinterpret_cast|short|sizeof|static_cast + |template|this|throw|try|typename|union + |using|virtual|void|extern)(\s|[;{(]) + + + + (Buffer|bool|int|uint|half|float|double)([1-4]?)(x[1-4])? (?=[(]|\s|\r|\n) + + + + (Texture) (?=[(]|\s|\r|\n) + + + + (sampler1D|sampler2D|sampler3D|samplerCUBE|sampler_state|SamplerState) + + + + (?i)(?<=\W)(VertexShader|PixelShader|GeometryShader| + AddressU|AddressV|AddressW|BorderColor|Filter|MaxAnisotropy| + MaxLOD|MinLOD|MipLODBias|ComparisonFunc|ComparisonFilter| + MipFilter|MinFilter|MagFilter|Texture|MaxLOD|MinLOD + + |AlphaBlendEnable|AlphaFunc|AlphaRef|AlphaTestEnable|BlendOp + |ColorWriteEnable|DepthBias|DestBlend|DitherEnable|FillMode + |LastPixel|ShadeMode|SlopeScaleDepthBias|SrcBlend + |StencilEnable|StencilFail|StencilFunc|StencilMask + |StencilPass|StencilRef|StencilWriteMask|StencilZFail + |TextureFactor|ZEnable|ZFunc + |Ambient|AmbientMaterialSource|Clipping|ClipPlaneEnable + |ColorVertex|CullMode|DiffuseMaterialSource|EmissiveMaterialSource + |FogColor|FogDensity|FogEnable|FogEnd|FogStart|FogTableMode|FogVertexMode + |IndexedVertexBlendEnable|Lighting|LocalViewer|MultiSampleAntialias|MultiSampleMask + |NormalizeNormals|PatchSegments|PointScale_A|PointScale_B|PointScale_C + |PointScaleEnable|PointSize|PointSize_Min|PointSize_Max|PointSpriteEnable + |RangeFogEnable|SpecularEnable|SpecularMaterialSource|TweenFactor|VertexBlend)(?=\s*[=]) + + + (?i)(?<=\W)(Wrap\d(\d)?) + + + + (?i)(?<=([=]\s*))(true|false|wrap|mirror|clamp|border|mirroronce + |none|point|linear|anisotropic|pyramidalquad|gaussianquad|convolutionmono + |zero|one|srccolor|invsrccolor|srcalpha|invsrcalpha|destalpha|invdestalpha + |destcolor|invdestcolor|srcalphasat|bothsrcalpha|bothinvsrcalpha + |blendfactor|invblendfactor|srccolor2|invsrccolor2 + |never|less|equal|lessequal|greater|notequal|greaterequal|always|wireframe|solid + |flat|gouraud|phong + |keep|replace|incrsat|decrsat|invert|decr|twosided|cw|ccw|exp|exp2|linear + |disable|1weights|2weights|3weights|tweening|0weights)(?=\s|[;{(]) + + + (ps|vs)_\d_\d(?=\s|[;{(]) + + + + (?<=([:]\s*)) + (BINORMAL|BLENDINDICES|BLENDWEIGHT|COLOR|NORMAL|POSITION| + PSIZE|TANGENT|TEXCOORD|TESSFACTOR|DEPTH|SV_ClipDistance| + SV_CullDistance|SV_Target) + (\d?) + + + + ([:]\s*)(POSITIONT + |FOG + |PSIZE + |VFACE + |VPOS + |SV_Coverage + |SV_Depth + |SV_DispatchThreadID + |SV_GroupID + |SV_GroupIndex + |SV_GroupThreadID + |SV_InsideTessFactor + |SV_IsFrontFace + |SV_OutputControlPointID + |SV_Position + |SV_RenderTargetArrayIndex + |SV_SampleIndex + |SV_TessFactor + |SV_ViewportArrayIndex + |SV_InstanceID + |SV_PrimitiveID + |SV_VertexID) + + + + (abs + |acos + |all + |AllMemoryBarrier + |AllMemoryBarrierWithGroupSync + |any + |asdouble + |asfloat + |asin + |asint + |asuint + |atan + |atan2 + |ceil + |clamp + |clip + |cos + |cosh + |countbits + |cross + |D3DCOLORtoUBYTE4 + |ddx + |ddx_coarse + |ddx_fine + |ddy + |ddy_coarse + |ddy_fine + |degrees + |determinant + |DeviceMemoryBarrier + |DeviceMemoryBarrierWithGroupSync + |distance + |dot + |dst + |EvaluateAttributeAtCentroid + |EvaluateAttributeAtSample + |EvaluateAttributeSnapped + |exp + |exp2 + |f16tof32 + |f32tof16 + |facetoforward + |firstbithigh + |firstbitlow + |floor + |fmod + |frac + |frexp + |fwidth + |GetRenderTargetSampleCount + |GetRenderTargetSamplePosition + |GroupMamoryBarrier + |GroupMamoryBarrierWithGroupSync + |InterlockedAdd + |InterlockedCompareExchange + |InterlockedCompareStore + |InterlockedExchange + |InterlockedMax + |InterlockedMin + |InterlockedOr + |InterlockedXor + |isfinite + |isinf + |isnan + |ldexp + |lerp + |lit + |log + |log10 + |log2 + |mad + |max + |min + |modf + |mul + |noise + |normalize + |pow + |Process2DQuadTessFactorsAvg + |Process2DQuadTessFactorsMax + |Process2DQuadTessFactorsMin + |ProcessIsolineTessFactors + |ProcessQuadTessFactorsAvg + |ProcessQuadTessFactorsMax + |ProcessQuadTessFactorsMin + |ProcessTriTessFactorsAvg + |ProcessTriTessFactorsMax + |ProcessTriTessFactorsMin + |radians + |rcp + |reflect + |refract + |reversebits + |round + |rsqrt + |saturate + |sign + |sin + |sincos + |sinh + |smoothstep + |sqrt + |step + |tan + |tanh + |tex1D + |tex1Dbias + |tex1Dgrad + |tex1Dlod + |tex1Dproj + |tex2D + |tex2Dbias + |tex2Dgrad + |tex2Dlod + |tex3D + |tex3Dbias + |tex3Dgrad + |tex3Dlod + |tex3Dproj + |texCUBE + |texCUBEbias + |texCUBEgrad + |texCUBElod + |texCUBEproj + |transpose + |trunc)(\s*[(]) + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/HTML-Mode.xshd b/src/HL/Resources/Light/HTML-Mode.xshd new file mode 100644 index 0000000..3be3b56 --- /dev/null +++ b/src/HL/Resources/Light/HTML-Mode.xshd @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + <!-- + --> + + + <script\ lang="JavaScript"> + </script> + + + <script\s.*?text/javascript.*?> + </script> + + + <script\ lang="JScript"> + </script> + + + <script\ lang="VBScript"> + </script> + + + <script> + </script> + + + <script[^\w\d_] + </script> + + + < + > + + + & + ; + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + aacute + agrave + acirc + amp + atilde + aring + auml + aelig + ccedil + copy + eacute + egrave + ecirc + euml + iacute + igrave + icirc + iuml + eth + gt + lt + nbsp + ntilde + oacute + ograve + ocirc + otilde + ouml + oslash + quot + reg + szlig + uacute + ugrave + ucirc + uuml + yacute + thorn + trade + yuml + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + / + + + = + + + !DOCTYPE + A + ABBR + ACRONYM + ADDRESS + APPLET + AREA + B + BASE + BASEFONT + BGSOUND + BDO + BIG + BLINK + BLOCKQUOTE + BODY + BR + BUTTON + CAPTION + CENTER + CITE + CODE + COL + COLGROUP + COMMENT + DD + DEL + DFN + DIR + DIV + DL + DT + EM + EMBED + FIELDSET + FONT + FORM + FRAME + FRAMESET + H + H1 + H2 + H3 + H4 + H5 + H6 + HEAD + HR + HTA:APPLICATION + HTML + I + IFRAME + IMG + INPUT + INS + ISINDEX + KBD + LABEL + LEGEnd + LI + LINK + LISTING + MAP + MARQUEE + MENU + META + MULTICOL + NEXTID + NOBR + NOFRAMES + NOSCRIPT + OBJECT + OL + OPTGROUP + OPTION + P + PARAM + PLAINTEXT + PRE + Q + S + SAMP + SCRIPT + SELECT + SERVER + SMALL + SOUND + SPACER + Span + STRONG + STYLE + SUB + SUP + TABLE + TBODY + TD + TEXTAREA + TEXTFLOW + TFOOT + TH + THEAD + TITLE + TR + TT + U + VAR + WBR + XMP + + + abbr + accept-charset + accept + accesskey + action + align + alink + alt + applicationname + archive + axis + background + behavior + bgcolor + bgproperties + border + bordercolor + bordercolordark + bordercolorligh + borderstyle + caption + cellpadding + cellspacing + char + charoff + charset + checked + cite + class + classid + clear + code + codetype + color + cols + colspan + compact + content + coords + data + datetime + declare + defer + dir + direction + disabled + dynsrc + enctype + face + for + frame + frameborder + framespacing + gutter + headers + height + href + hreflang + hspace + http-equiv + icon + id + ismap + label + language + leftmargin + link + longdesc + loop + lowsrc + marginheight + marginwidth + maximizebutton + maxlength + media + method + methods + minimizebutton + multiple + name + nohref + noresize + noshade + nowrap + object + onabort + onblur + onchange + onclick + ondblclick + onerror + onfocus + onkeydown + onkeypress + onkeyup + onload + onmousedown + onmousemove + onmouseout + onmouseover + onmouseup + onreset + onselect + onsubmit + onunload + profile + prompt + readonly + rel + rev + rows + rowspan + rules + runat + scheme + scope + scrollamount + scrolldelay + scrolling + selected + shape + showintaskbar + singleinstance + size + span + src + standby + start + style + summary + sysmenu + tabindex + target + text + title + topmargin + type + urn + usemap + valign + value + valuetype + version + vlink + vrml + vspace + width + windowstate + wrap + + + " + " + + + ' + ' + + [\d\w_]+(?=(\s*=)) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/INI.xshd b/src/HL/Resources/Light/INI.xshd new file mode 100644 index 0000000..e670921 --- /dev/null +++ b/src/HL/Resources/Light/INI.xshd @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + ' + ' + + + + " + " + + + + + ; + + + \# + + + + \[ + \] + + + + ^[0-9A-Z\-]+ + = + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+[0-9]+[ ?,.;()\[\]{}+\-/%*<>^+~!|&]+\n + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/Java-Mode.xshd b/src/HL/Resources/Light/Java-Mode.xshd new file mode 100644 index 0000000..dd5053e --- /dev/null +++ b/src/HL/Resources/Light/Java-Mode.xshd @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + [?,.()\[\]{}+\-/%*<>^!|]+ + + + this + super + + + new + instanceof + true + false + + + else + if + switch + case + + + do + for + while + + + break + continue + default + goto + return + + + try + throw + catch + finally + + + boolean + double + int + short + long + float + byte + char + + + class + interface + object + + + void + + + abstract + const + static + final + native + extends + implements + volatile + transient + throws + strictfp + synchronized + + + public + protected + private + + + package + import + + + null + + + // + + + /\* + \*/ + + + " + " + + + + + + ' + ' + + + + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + + TODO + + + @author + @version + @param + @return + @exception + @throws + @see + @since + @serial + @serialField + @serialData + @deprecated + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/JavaScript-Mode.xshd b/src/HL/Resources/Light/JavaScript-Mode.xshd new file mode 100644 index 0000000..f30543c --- /dev/null +++ b/src/HL/Resources/Light/JavaScript-Mode.xshd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + break + continue + delete + else + for + function + if + in + new + return + this + typeof + var + void + while + with + abstract + boolean + byte + case + catch + char + class + const + debugger + default + do + double + enum + export + extends + final + finally + float + goto + implements + import + instanceof + int + interface + long + native + package + private + protected + public + short + static + super + switch + synchronized + throw + throws + transient + try + volatile + + + Array + Boolean + Date + Function + Global + Math + Number + Object + RegExp + String + + + false + null + true + NaN + Infinity + + + eval + parseInt + parseFloat + escape + unescape + isNaN + isFinite + + + // + + + /\* + \*/ + + + + / + / + + + + + + " + " + + + + + + ' + ' + + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + \ No newline at end of file diff --git a/src/HL/Resources/Light/Log.xshd b/src/HL/Resources/Light/Log.xshd new file mode 100644 index 0000000..9b5458a --- /dev/null +++ b/src/HL/Resources/Light/Log.xshd @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + Info + Information + Trace + Debug + + + + Error + Warn + Warning + Exception + Fatal + + + + ' + ' + + + + " + " + + + + + ; + + + \# + + + + \[ + \] + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+[0-9]+[ ?,.;()\[\]{}+\-/%*<>^+~!|&]+\n + + + + + [0-9][0-9][0-9][0-9]\-[0-9][0-9]\-[0-9][0-9] + + + + + [0-9][0-9]\:[0-9][0-9]\:[0-9][0-9]\.[0-9][0-9][0-9] + + + + + [0-9][0-9]\:[0-9][0-9]\:[0-9][0-9] + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/MarkDown-Mode.xshd b/src/HL/Resources/Light/MarkDown-Mode.xshd new file mode 100644 index 0000000..ead5045 --- /dev/null +++ b/src/HL/Resources/Light/MarkDown-Mode.xshd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + ^\#.* + + + \*\*.*\*\* + + + __.*__ + + + \*(?![ ]).*\* + + + _.*_ + + + `.*` + + + ^\t + ^(?!\t) + + + ^[ ]{4} + ^(?![ ]{4}) + + + ^> + ^(?!>) + + + \!\[.*\]\[.*\] + + + \[.*\]\(.*\) + + + \[.*\]\[.*\] + + + [ ]{2}$ + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/PHP-Mode.xshd b/src/HL/Resources/Light/PHP-Mode.xshd new file mode 100644 index 0000000..a594b60 --- /dev/null +++ b/src/HL/Resources/Light/PHP-Mode.xshd @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + \# + + + + // + + + + /\* + \*/ + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + \b0[0-9]+ # octal number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.:;()\[\]{}+\-/%*<>&^!|~@]+ + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + ' + ' + + + + + + + + " + " + + + + + + + + + <<<\"?[\d\w_]+\"?$ + ^[\d\w_]+; + + + + + <<<\'[\d\w_]+\'$ + ^[\d\w_]+; + + + + global + my + var + + + + and + or + new + clone + instanceof + xor + true + false + + + + else + else + switch + case + endif + elseif + + + + do + for + foreach + while + endwhile + exit + + + + break + continue + default + goto + return + + + + require + include + require + include + function + + + + int + integer + real + double + float + string + array + object + + + + class + void + + + + public + private + + + diff --git a/src/HL/Resources/Light/PLSQL.xshd b/src/HL/Resources/Light/PLSQL.xshd new file mode 100644 index 0000000..15adf2c --- /dev/null +++ b/src/HL/Resources/Light/PLSQL.xshd @@ -0,0 +1,505 @@ + + + + + + + + + + + + -- + + + + /\* + \*/ + + + + ' + ' + + + + + + + + " + " + + + + + + + + all + alter + and + any + array + arrow + as + asc + at + begin + between + by + case + check + clusters + cluster + colauth + columns + compress + connect + crash + create + current + decimal + declare + default + delete + desc + distinct + drop + else + end + exception + exclusive + exists + exec + fetch + form + for + from + goto + grant + group + having + identified + if + in + indexes + index + insert + intersect + into + is + like + lock + minus + mode + nocompress + not + nowait + null + of + on + option + or + order + overlaps + prior + procedure + public + range + record + resource + revoke + select + share + size + sql + start + subtype + tabauth + table + then + to + type + union + unique + update + use + values + view + views + when + where + with + + + + a + add + agent + aggregate + array + attribute + authid + avg + bfile_base + binary + blob_base + block + body + both + bound + bulk + byte + c + call + calling + cascade + char + char_base + character + charsetform + charsetid + charset + clob_base + close + collect + comment + commit + committed + compiled + constant + constructor + context + convert + count + cursor + customdatum + dangling + data + date + date_base + day + define + deterministic + double + duration + element + elsif + empty + escape + except + exceptions + execute + exit + external + final + fixed + float + forall + force + function + general + hash + heap + hidden + hour + immediate + including + indicator + indices + infinite + instantiable + int + interface + interval + invalidate + isolation + java + language + large + leading + length + level + library + like2 + like4 + likec + limit + limited + local + long + loop + map + max + maxlen + member + merge + min + minute + mod + modify + month + multiset + name + nan + national + native + nchar + new + nocopy + number_base + object + ocicoll + ocidatetime + ocidate + ociduration + ociinterval + ociloblocator + ocinumber + ociraw + ocirefcursor + ociref + ocirowid + ocistring + ocitype + only + opaque + open + operator + oracle + oradata + organization + orlany + orlvary + others + out + overriding + package + parallel_enable + parameter + parameters + partition + pascal + pipe + pipelined + pragma + precision + private + raise + range + raw + read + record + ref + reference + rem + remainder + rename + result + return + returning + reverse + rollback + row + sample + save + savepoint + sb1 + sb2 + sb4 + second + segment + self + separate + sequence + serializable + set + short + size_t + some + sparse + sqlcode + sqldata + sqlname + sqlstate + standard + static + stddev + stored + string + struct + style + submultiset + subpartition + substitutable + subtype + sum + synonym + tdo + the + time + timestamp + timezone_abbr + timezone_hour + timezone_minute + timezone_region + trailing + transac + transactional + trusted + type + ub1 + ub2 + ub4 + under + unsigned + untrusted + use + using + valist + value + variable + variance + varray + varying + void + while + work + wrapped + write + year + zone + + + + abs + greatest + sin + acos + group_id + sinh + add_months + hextoraw + soundex + ascii + initcap + sqlcode + asciistr + instr + sqlerrm + asin + lag + sqrt + atan + last_day + stddev + atan2 + lead + substr + avg + least + sum + bfilename + length + sys_context + bin_to_num + lnnvl + sysdate + bitand + ln + systimestamp + cardinality + localtimestamp + tan + case + statement + log + tanh + cast + lower + to_char + ceil + lpad + to_clob + chartorowid + ltrim + to_date + chr + max + to_dsinterval + coalesce + median + to_lob + compose + min + to_multi_byte + concat + mod + to_nclob + concat + with + months_between + to_number + convert + nanvl + to_single_byte + corr + new_time + to_timestamp + cos + next_day + to_timestamp_tz + cosh + nullif + to_yminterval + count + numtodsinterval + translate + covar_pop + numtoyminterval + trim + covar_samp + nvl + trunc + (dates) + cume_dist + nvl2 + trunc + (numbers) + current_date + power + tz_offset + current_timestamp + rank + uid + dbtimezone + rawtohex + upper + decode + remainder + user + decompose + replace + userenv + dense_rank + round + (dates) + var_pop + dump + round + (numbers) + var_samp + exp + rpad + variance + extract + rtrim + vsize + floor + sessiontimezone + from_tz + sign + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/Pascal.xshd b/src/HL/Resources/Light/Pascal.xshd new file mode 100644 index 0000000..dff23f1 --- /dev/null +++ b/src/HL/Resources/Light/Pascal.xshd @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + @param + @returns + + + + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&\#]+ + + + + // + + + + { + } + + + + " + " + + + + + + + + ' + ' + + + + + + + + integer + byte + real + boolean + char + shortint + word + longint + string + + + + and + not + or + in + div + mod + + + + array + const + downto + file + forward + label + main + nil + packed + record + repeat + set + to + type + until + var + begin + case + do + else + for + function + goto + if + procedure + program + then + of + end + while + with + + + + abs + arctan + chr + cos + dispose + eof + eoln + exp + false + get + input + ln + maxint + new + odd + ord + output + page + pred + put + read + readln + reset + rewrite + round + sin + sqr + sqrt + succ + text + true + trunc + write + writeln + + + [\d\w_]+(?=(\s*\()) + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + diff --git a/src/HL/Resources/Light/Patch-Mode.xshd b/src/HL/Resources/Light/Patch-Mode.xshd new file mode 100644 index 0000000..d81a15b --- /dev/null +++ b/src/HL/Resources/Light/Patch-Mode.xshd @@ -0,0 +1,36 @@ + + + + + + + + + + + + Index:\s + + + == + + + --- + + + \+\+\+ + + + @@ + + + - + + + \+ + + + \s + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/PowerShell.xshd b/src/HL/Resources/Light/PowerShell.xshd new file mode 100644 index 0000000..d0becb7 --- /dev/null +++ b/src/HL/Resources/Light/PowerShell.xshd @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + \# + + + + <\# + \#> + + + + " + " + + + + + + + + ' + ' + + + + + + + + @" + "@ + + + + + + + + while + param + end + define + else + from + foreach + var + dynamicparam + filter + dp + until + for + exit + switch + process + begin + elseif + if + in + data + class + using + function + + + + catch + finally + throw + trap + try + + + + break + continue + return + + + + class + + + + -not + -band + -bor + -replace + -ireplace + -creplace + -and + -or + -is + -isnot + -as + -lt + -le + -gt + -ge + -eq + -ne + -contains + -notcontains + -like + -notlike + -match + -notmatch + + + + \$[\d\w_]+ + + + + [\w]+-[\w]+ + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + diff --git a/src/HL/Resources/Light/Python-Mode.xshd b/src/HL/Resources/Light/Python-Mode.xshd new file mode 100644 index 0000000..12b1dcf --- /dev/null +++ b/src/HL/Resources/Light/Python-Mode.xshd @@ -0,0 +1,104 @@ + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + \# + + + + ''' + ''' + + + """ + """ + + + + " + " + + + + + + ' + ' + + + + + + + and + as + assert + break + class + continue + def + del + elif + else + except + exec + False + finally + for + from + global + if + import + in + is + lambda + None + nonlocal + not + or + pass + print + raise + return + True + try + while + with + yield + async + await + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + \b0[xX][0-9a-fA-F]+ # hex number + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + diff --git a/src/HL/Resources/Light/Ruby.xshd b/src/HL/Resources/Light/Ruby.xshd new file mode 100644 index 0000000..7c8d479 --- /dev/null +++ b/src/HL/Resources/Light/Ruby.xshd @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + \b0[xX][0-9a-fA-F]+|(\b\d+(\.[0-9]+)?|\.[0-9]+)([eE][+-]?[0-9]+)? + + + [?,.:;()\[\]{}+\-/%*<>^=~!]+ + + + + ' + ' + + + + + + + """ + """ + + + \=begin + \=end + + + \# + + + " + " + + + + + + + + abort + Array + at_exit + autoload + binding + callcc + caller + chomp + chop + eval + exec + exit + fail + Float + fork + format + gets + global_variables + gsub + Integer + lambda + proc + load + local_variables + loop + open + p + print + print + printf + putc + puts + rand + readline + scan + select + set_trace_func + sleep + split + sprintf + srand + String + syscall + system + sub + test + throw + trace_var + trap + untrace_var + + + + class + module + public + protected + private + + + + begin + rescue + ensure + raise + catch + + + + def + end + undef + + + + for + do + in + while + until + + + + break + yield + redo + return + retry + next + + + + and + not + or + + + + nil + + + + elsif + else + if + then + case + unless + + + + true + false + + + + defined + + + + self + + + + super + + + + import + alias + + + + include + require + + + [\d\w_]+(?=(\s*\()) + @([\w]+) + &([\w]+) + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + =begin + =end + + + TODO + FIXME + + + HACK + UNDONE + + + =begin + =end + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/TSQL-Mode.xshd b/src/HL/Resources/Light/TSQL-Mode.xshd new file mode 100644 index 0000000..e73e230 --- /dev/null +++ b/src/HL/Resources/Light/TSQL-Mode.xshd @@ -0,0 +1,618 @@ + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + -- + + + + /\* + \*/ + + + + ' + ' + + + + + + + abs + absolute + access + acos + add + add_months + adddate + admin + after + aggregate + all + allocate + alter + and + any + app_name + are + array + as + asc + ascii + asin + assertion + at + atan + atn2 + audit + authid + authorization + autonomous_transaction + avg + before + begin + benchmark + between + bfilename + bigint + bin + binary + binary_checksum + binary_integer + bit + bit_count + bit_and + bit_or + blob + body + boolean + both + breadth + bulk + by + call + cascade + cascaded + case + cast + catalog + ceil + ceiling + char + char_base + character + charindex + chartorowid + check + checksum + checksum_agg + chr + class + clob + close + cluster + coalesce + col_length + col_name + collate + collation + collect + column + comment + commit + completion + compress + concat + concat_ws + connect + connection + constant + constraint + constraints + constructorcreate + contains + containsable + continue + conv + convert + corr + corresponding + cos + cot + count + count_big + covar_pop + covar_samp + create + cross + cube + cume_dist + current + current_date + current_path + current_role + current_time + current_timestamp + current_user + currval + cursor + cycle + data + datalength + databasepropertyex + date + date_add + date_format + date_sub + dateadd + datediff + datename + datepart + datetime + day + db_id + db_name + deallocate + dec + declare + decimal + decode + default + deferrable + deferred + degrees + delete + dense_rank + depth + deref + desc + describe + descriptor + destroy + destructor + deterministic + diagnostics + dictionary + disconnect + difference + distinct + do + domain + double + drop + dump + dynamic + each + else + elsif + empth + encode + encrypt + end + end-exec + equals + escape + every + except + exception + exclusive + exec + execute + exists + exit + exp + export_set + extends + external + extract + false + fetch + first + first_value + file + float + floor + file_id + file_name + filegroup_id + filegroup_name + filegroupproperty + fileproperty + for + forall + foreign + format + formatmessage + found + freetexttable + from + from_days + fulltextcatalog + fulltextservice + function + general + get + get_lock + getdate + getansinull + getutcdate + global + go + goto + grant + greatest + group + grouping + having + heap + hex + hextoraw + host + host_id + host_name + hour + ident_incr + ident_seed + ident_current + identified + identity + if + ifnull + ignore + immediate + in + increment + index + index_col + indexproperty + indicator + initcap + initial + initialize + initially + inner + inout + input + insert + instr + instrb + int + integer + interface + intersect + interval + into + is + is_member + is_srvrolemember + is_null + is_numeric + isdate + isnull + isolation + iterate + java + join + key + lag + language + large + last + last_day + last_value + lateral + lcase + lead + leading + least + left + len + length + lengthb + less + level + like + limit + limited + ln + lpad + local + localtime + localtimestamp + locator + lock + log + log10 + long + loop + lower + ltrim + make_ref + map + match + max + maxextents + mid + min + minus + minute + mlslabel + mod + mode + modifies + modify + module + month + months_between + names + national + natural + naturaln + nchar + nclob + new + new_time + newid + next + next_day + nextval + no + noaudit + nocompress + nocopy + nolock + none + not + nowait + null + nullif + number + number_base + numeric + nvl + nvl2 + object + object_id + object_name + object_property + ocirowid + oct + of + off + offline + old + on + online + only + opaque + open + operator + operation + option + or + ord + order + ordinalityorganization + others + out + outer + output + package + pad + parameter + parameters + partial + partition + path + pctfree + percent_rank + pi + pls_integer + positive + positiven + postfix + pow + power + pragma + precision + prefix + preorder + prepare + preserve + primary + prior + private + privileges + procedure + public + radians + raise + rand + range + rank + ratio_to_export + raw + rawtohex + read + reads + real + record + recursive + ref + references + referencing + reftohex + relative + release + release_lock + rename + repeat + replace + resource + restrict + result + return + returns + reverse + revoke + right + rollback + rollup + round + routine + row + row_number + rowid + rowidtochar + rowlabel + rowlock + rownum + rows + rowtype + rpad + rtrim + savepoint + schema + scroll + scope + search + second + section + seddev_samp + select + separate + sequence + session + session_user + set + sets + share + sign + sin + sinh + size + smallint + some + soundex + space + specific + specifictype + sql + sqlcode + sqlerrm + sqlexception + sqlstate + sqlwarning + sqrt + start + state + statement + static + std + stddev + stdev_pop + strcmp + structure + subdate + substr + substrb + substring + substring_index + subtype + successful + sum + synonym + sys_context + sys_guid + sysdate + system_user + table + tan + tanh + temporary + terminate + than + then + time + timestamp + timezone_abbr + timezone_minute + timezone_hour + timezone_region + tinyint + to + top + to_char + to_date + to_days + to_number + to_single_byte + trailing + transaction + translate + translation + treat + trigger + trim + true + trunc + truncate + type + ucase + uid + under + union + unique + unknown + unnest + update + upper + usage + use + user + userenv + using + validate + value + values + var_pop + var_samp + varbinary + varchar + varchar2 + variable + variance + varying + view + vsize + when + whenever + where + with + without + while + work + write + year + zone + + + diff --git a/src/HL/Resources/Light/TXT.xshd b/src/HL/Resources/Light/TXT.xshd new file mode 100644 index 0000000..7312fe7 --- /dev/null +++ b/src/HL/Resources/Light/TXT.xshd @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /\* + \*/ + + + + BUG FIX + BUG + BUGS + HACK + TODO + TODOS + + + + DONE + TICK + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + [ ?,.;()\[\]{}+\-/%*<>^+~!|&]+[0-9]+[ ?,.;()\[\]{}+\-/%*<>^+~!|&]+\n + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/Tex-Mode.xshd b/src/HL/Resources/Light/Tex-Mode.xshd new file mode 100644 index 0000000..b10144b --- /dev/null +++ b/src/HL/Resources/Light/Tex-Mode.xshd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + Bug + Problem + + + + + + \d + + + + \$ + \$ + + + + + \\\( + \\\) + + + + + \\\[ + \\\] + + + + + \[ + \] + + [^\\] + + + + + (&)|(\\\ )|(\\\\)|(\\@)|(\\\$)|(\\&)|(\\%)|(\\\#)|(\\{)|(\\})|(\\/) + + (\\[\w]+) + + ({[\w]+.*}) + + (%)$ + + + + % + + + ({)|(}) + + + + + + + + + + % + + + + + + + ) + ) + { + } + [ + ] + = + ! + + + - + / + * + > + < + & + | + ^ + ~ + . + , + ; + ? + : + ' + + ` + + + + + + + diff --git a/src/HL/Resources/Light/VB-Mode.xshd b/src/HL/Resources/Light/VB-Mode.xshd new file mode 100644 index 0000000..60e23da --- /dev/null +++ b/src/HL/Resources/Light/VB-Mode.xshd @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + " + " + + + + + + (?<=(^\s*))\# + + + (?<!(^\s*))\# + \# + + + ''' + + + ' + + + \bREM\b + + + Boolean + Byte + Char + Date + Decimal + Double + Integer + Long + Object + SByte + Short + Single + String + UInteger + ULong + UShort + Variant + + + AddressOf + And + AndAlso + Await + Is + IsNot + Like + Mod + New + Not + Or + OrElse + Xor + + + False + Me + MyBase + MyClass + Nothing + True + + + CBool + CByte + CChar + CDate + CDbl + CDec + CInt + CLng + CObj + CSByte + CShort + CSng + CStr + CType + CUInt + CULng + CUShort + DirectCast + GetType + GetXmlNamespace + IIf + TryCast + TypeOf + + + AddHandler + Alias + As + ByRef + ByVal + Call + Case + Catch + Class + Const + Continue + Declare + Default + Delegate + Dim + Do + Each + Else + ElseIf + End + EndIf + Enum + Erase + Error + Event + Exit + Finally + For + Friend + Function + Get + Global + GoSub + GoTo + Handles + If + Implements + Imports + In + Inherits + Interface + Let + Lib + Loop + Module + MustInherit + MustOverride + Namespace + Narrowing + New + Next + NotInheritable + NotOverridable + Of + On + Operator + Option + Optional + Overloads + Overridable + Overrides + ParamArray + Partial + Private + Property + Protected + Public + RaiseEvent + ReadOnly + ReDim + RemoveHandler + Resume + Return + Select + Set + Shadows + Shared + Static + Step + Stop + Structure + Sub + SyncLock + Then + Throw + To + Try + Using + Wend + When + While + Widening + With + WithEvents + WriteOnly + + + Aggregate + Ansi + Ascending + Async + Auto + Binary + By + Compare + Custom + Descending + Distinct + Equals + Explicit + From + Group + Infer + Into + Iterator + Join + Key + Off + Preserve + Skip + Strict + Take + Text + Unicode + Until + Where + Yield + + + + + Const + Else + ElseIf + End + ExternalChecksum + ExternalSource + If + Region + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/XML-Mode.xshd b/src/HL/Resources/Light/XML-Mode.xshd new file mode 100644 index 0000000..8f0bdef --- /dev/null +++ b/src/HL/Resources/Light/XML-Mode.xshd @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + <!-- + --> + + + <!\[CDATA\[ + ]]> + + + <!DOCTYPE + > + + + <\? + \?> + + + < + > + + + + " + "|(?=<) + + + ' + '|(?=<) + + [\d\w_\-\.]+(?=(\s*=)) + = + + + + + + + + & + [\w\d\#]+ + ; + + + + & + [\w\d\#]* + #missing ; + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/XmlDoc.xshd b/src/HL/Resources/Light/XmlDoc.xshd new file mode 100644 index 0000000..270ec2b --- /dev/null +++ b/src/HL/Resources/Light/XmlDoc.xshd @@ -0,0 +1,57 @@ + + + + + + + + + + < + > + + + " + " + + + / + | + = + + + c + code + example + exception + list + para + param + paramref + permission + remarks + returns + see + seealso + summary + value + + type + name + cref + item + term + description + listheader + typeparam + typeparamref + + + + + + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/scheme.xshd b/src/HL/Resources/Light/scheme.xshd new file mode 100644 index 0000000..5eda5e8 --- /dev/null +++ b/src/HL/Resources/Light/scheme.xshd @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + ; + + + \#\| + \|\# + + + + + import + export + library + + + + define + set! + lambda + begin + if + cond + let + letrec + + + + else + + + + map + cons + car + + + + null + value + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | + ( \b\d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + diff --git a/src/HL/Resources/Light/squirrel.xshd b/src/HL/Resources/Light/squirrel.xshd new file mode 100644 index 0000000..665a09e --- /dev/null +++ b/src/HL/Resources/Light/squirrel.xshd @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + TODO + FIXME + + + HACK + UNDONE + + + + + + + \# + + + + /// + + + + + + + + // + + + + /\* + \*/ + + + + " + " + + + + + + + + @" + " + + + + + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+ + + + + GGen_Point + GGen_Path + GGen_Amplitudes + GGen_Data_2D + GGen_Data_1D + + + + else + if + switch + case + default + for + while + break + local + catch + clone + continue + const + delegate + delete + else + enum + extends + for + function + null + resume + return + switch + this + throw + typeof + parent + yield + constructor + vargc + vargv + instanceof + true + false + static + + + + + \b + [\d\w_]+ # an identifier + (?=\s*\() # followed by ( + + + + + \b0[xX][0-9a-fA-F]+ # hex number + | \b + ( \d+(\.[0-9]+)? #number with optional floating point + | \.[0-9]+ #or just starting with floating point + ) + ([eE][+-]?[0-9]+)? # optional exponent + + + \ No newline at end of file diff --git a/src/HL/Resources/Light/vtl.xshd b/src/HL/Resources/Light/vtl.xshd new file mode 100644 index 0000000..f84d515 --- /dev/null +++ b/src/HL/Resources/Light/vtl.xshd @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + ' + ' + + + + " + " + + + + \#\# + + + + \#\* + \*\# + + + + \# + [\w\d]+ + + + \$([\d\w]+)([.])([\d\w]+) + + \$([\d\w]+)([.])([\d\w]+) + + ([.])([\d\w]+) + + \$([\d\w]+) + + + [?,;()\[\]{}+\-/%*<>^+~!|&]+ + + + + [?,.;()\[\]{}+\-/%*<>^+~!|&]+[0-9]+[ ?,.;()\[\]{}+\-/%*<>^+~!|&]+\n + + + + + \ No newline at end of file diff --git a/src/HL/Resources/Themes/Dark.xshtd b/src/HL/Resources/Themes/Dark.xshtd new file mode 100644 index 0000000..64fea25 --- /dev/null +++ b/src/HL/Resources/Themes/Dark.xshtd @@ -0,0 +1,549 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HL/Resources/Themes/TrueBlue.xshtd b/src/HL/Resources/Themes/TrueBlue.xshtd new file mode 100644 index 0000000..08924b8 --- /dev/null +++ b/src/HL/Resources/Themes/TrueBlue.xshtd @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HL/Resources/Themes/VS2019_Dark.xshtd b/src/HL/Resources/Themes/VS2019_Dark.xshtd new file mode 100644 index 0000000..784f9c4 --- /dev/null +++ b/src/HL/Resources/Themes/VS2019_Dark.xshtd @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HL/Xshtd/IXshtdVisitor.cs b/src/HL/Xshtd/IXshtdVisitor.cs new file mode 100644 index 0000000..d2bfdac --- /dev/null +++ b/src/HL/Xshtd/IXshtdVisitor.cs @@ -0,0 +1,68 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd +{ + /// + /// Implements an interface for usage in a Visitor pattern based implementation. + /// This visitor pattern can be used to visit the elements of an XSHTD element tree. + /// + /// A visitor pattern can be used in many ways, here its used for syntax checks and + /// object conversion (from POCO XML object to non-xml .net object). + /// + public interface IXshtdVisitor + { + /// + /// Implements the visitor for a named color ( object) + /// that is contained in a object. + /// + /// + /// + /// + object VisitColor(XshtdSyntaxDefinition syntax, XshtdColor color); + + /// + /// Implements the visitor for the object. + /// + /// the element to be visited. + /// + object VisitSyntaxDefinition(XshtdSyntaxDefinition syntax); + + /// + /// Implements the visitor for the object. + /// + /// the element to be visited. + /// + object VisitGlobalStyles(XshtdGlobalStyles globStyles); + + /// + /// Implements the visitor for the object + /// contained in a object. + /// + /// + /// + /// + object VisitGlobalStyle(XshtdGlobalStyles globStyles, XshtdGlobalStyle style); + } +} diff --git a/src/HL/Xshtd/XhstdThemeDefinition.cs b/src/HL/Xshtd/XhstdThemeDefinition.cs new file mode 100644 index 0000000..88fd51c --- /dev/null +++ b/src/HL/Xshtd/XhstdThemeDefinition.cs @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd +{ + using System; + using System.Collections.Generic; + using ICSharpCode.AvalonEdit.Utils; + + /// + /// An Xml highlighting theme element. + /// + /// for equivalent run-time object. + /// + [Serializable] + public class XhstdThemeDefinition : XshtdElement + { + /// + /// Creates a new XhstdThemeDefinition object. + /// + public XhstdThemeDefinition() + { + this.Elements = new NullSafeCollection(); + this.GlobalStyleElements = new XshtdGlobalStyles(); + } + + /// + /// Gets/sets the highlighting theme definition name (eg. 'Dark', 'TrueBlue') + /// as stated in the Name attribute of the xshtd (xs highlighting theme definition) file. + /// + public string Name { get; set; } + + /// + /// Gets the collection of elements. + /// + public IList Elements { get; private set; } + + /// + /// Gets the collection of elements. + /// + public XshtdGlobalStyles GlobalStyleElements { get; private set; } + + /// + /// Applies the visitor to all elements. + /// + public override object AcceptVisitor(IXshtdVisitor visitor) + { + foreach (XshtdElement element in Elements) + { + element.AcceptVisitor(visitor); + } + + // Visit Global Styles + foreach (XshtdElement element in GlobalStyleElements.Elements) + { + element.AcceptVisitor(visitor); + } + + return null; + } + } +} diff --git a/src/HL/Xshtd/XmlHighlightingThemeDefinition.cs b/src/HL/Xshtd/XmlHighlightingThemeDefinition.cs new file mode 100644 index 0000000..74cd98e --- /dev/null +++ b/src/HL/Xshtd/XmlHighlightingThemeDefinition.cs @@ -0,0 +1,397 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Xshtd +{ + using HL.HighlightingTheme; + using HL.Xshtd.interfaces; + using ICSharpCode.AvalonEdit.Highlighting; + using System.Collections.Generic; + using System.Diagnostics; + + /// + /// Implements a highlighting theme definition object that provides all run-time + /// relevant properties and methods to work with themes in the context of highlightings. + /// + /// for equivalent Xml persistance layer object. + /// + internal class XmlHighlightingThemeDefinition : IHighlightingThemeDefinition + { + #region fields + private Dictionary syntaxDefDict; + private Dictionary _GlobalStyles; + private readonly XhstdThemeDefinition _xshtd; + #endregion fields + + #region ctors + /// + /// Class constructor + /// + public XmlHighlightingThemeDefinition(XhstdThemeDefinition xshtd, + IHighlightingThemeDefinitionReferenceResolver resolver) + : this() + { + // Create HighlightingRuleSet instances + xshtd.AcceptVisitor(new RegisterNamedElementsVisitor(this)); + + // Translate elements within the rulesets (resolving references and processing imports) + xshtd.AcceptVisitor(new TranslateElementVisitor(this, resolver)); + + _xshtd = xshtd; + } + + /// + /// Class constructor + /// + protected XmlHighlightingThemeDefinition() + { + syntaxDefDict = new Dictionary(); + _GlobalStyles = new Dictionary(); + } + #endregion ctors + + #region properties + /// + /// Gets/sets the highlighting theme definition name (eg. 'Dark', 'TrueBlue') + /// as stated in the Name attribute of the xshtd (xs highlighting theme definition) file. + /// + public string Name { get { return _xshtd.Name; } } + + /// + /// Gets all global stayles in the collection of global styles. + /// + public IEnumerable GlobalStyles + { + get + { + return _GlobalStyles.Values; + } + } + #endregion properties + + #region methods + /// + /// Gets the syntaxdefinition colors that should be applied for a certain highlighting (eg 'C#') + /// within this theme (eg TrueBlue). + /// + /// + /// + public SyntaxDefinition GetNamedSyntaxDefinition(string name) + { + SyntaxDefinition item = null; + syntaxDefDict.TryGetValue(name, out item); + + return item; + } + + /// + /// Gets a highlighting color based on the name of the syntax definition + /// and the name of the color that should be contained in it. + /// + /// + /// + /// + public HighlightingColor GetNamedColor(string synDefName, string colorName) + { + var synDef = GetNamedSyntaxDefinition(synDefName); + if (synDef == null) + return null; + + return synDef.ColorGet(colorName); + } + + /// + /// Gets an enumeration of all highlighting colors that are defined + /// for this highlighting pattern (eg. C#) as part of a highlighting theme (eg 'True Blue'). + /// + public IEnumerable NamedHighlightingColors(string synDefName) + { + var synDef = GetNamedSyntaxDefinition(synDefName); + if (synDef == null) + return new List(); + + return synDef.NamedHighlightingColors; + } + + /// + /// Helper method to generate a + /// containing more insights (line number, coloumn) to verify the actual problem. + /// + /// + /// + /// + private static System.Exception Error(XshtdElement element, string message) + { + if (element.LineNumber > 0) + return new HighlightingDefinitionInvalidException( + "Error at line " + element.LineNumber + ":\n" + message); + else + return new HighlightingDefinitionInvalidException(message); + } + #endregion methods + + #region private classes + /// + /// Implements the visitor pattern based on the interface + /// to register all elements of a given XML element tree and check whether their syntax + /// is as expected or not. + /// + sealed class RegisterNamedElementsVisitor : IXshtdVisitor + { + #region fields + private readonly XmlHighlightingThemeDefinition def; + #endregion fields + + #region ctors + /// + /// Class constructor + /// + public RegisterNamedElementsVisitor(XmlHighlightingThemeDefinition def) + : this() + { + this.def = def; + } + + /// + /// Class constructor + /// + private RegisterNamedElementsVisitor() + { + } + #endregion ctors + + #region methods + /// + /// Implements the visitor for the object. + /// + /// + /// + public object VisitSyntaxDefinition(XshtdSyntaxDefinition syntax) + { + if (syntax.Name != null) + { + if (syntax.Name.Length == 0) + throw Error(syntax, "Name must not be the empty string"); + + if (def.syntaxDefDict.ContainsKey(syntax.Name)) + throw Error(syntax, "Duplicate syntax definition name '" + syntax.Name + "'."); + + def.syntaxDefDict.Add(syntax.Name, new SyntaxDefinition()); + } + + syntax.AcceptElements(this); + + return null; + } + + /// + /// Implements the visitor for a named color ( object) + /// that is contained in a object. + /// + /// Method checks if given color name is unique and adds the color into the internal + /// collection of inique colors if it is. + /// + /// + /// + /// Always returns null. Throws a + /// if color name is a duplicate. + public object VisitColor(XshtdSyntaxDefinition syntax, XshtdColor color) + { + if (color.Name != null) + { + if (color.Name.Length == 0) + throw Error(color, "Name must not be the empty string"); + + if (syntax == null) + throw Error(syntax, "Syntax Definition for theme must not be null"); + + SyntaxDefinition synDef; + if (def.syntaxDefDict.TryGetValue(syntax.Name, out synDef) == false) + throw Error(syntax, "Themed Syntax Definition does not exist '" + syntax.Name + "'."); + + if (synDef.ColorGet(color.Name) == null) + synDef.ColorAdd(new HighlightingColor() { Name = color.Name }); + else + throw Error(color, "Duplicate color name '" + color.Name + "'."); + } + + return null; + } + + /// + /// Implements the visitor for the object. + /// + /// the element to be visited. + /// + public object VisitGlobalStyles(XshtdGlobalStyles globStyles) + { + globStyles.AcceptElements(this); + + return null; + } + + public object VisitGlobalStyle(XshtdGlobalStyles globStyles, XshtdGlobalStyle style) + { + if (style.TypeName != null) + { + if (style.TypeName.Length == 0) + throw Error(style, "Name must not be the empty string"); + + if (globStyles == null) + throw Error(globStyles, "GlobalStyles parameter must not be null"); + + GlobalStyle globDef; + if (def._GlobalStyles.TryGetValue(style.TypeName, out globDef) == true) + throw Error(style, "GlobalStyle definition '" + style.TypeName + "' has duplicates."); + + globDef = new GlobalStyle(style.TypeName); + globDef.backgroundcolor = style.background; + globDef.foregroundcolor = style.foreground; + globDef.bordercolor = style.bordercolor; + + globDef.Freeze(); + + def._GlobalStyles.Add(style.TypeName, new GlobalStyle(style.TypeName)); + } + + return null; + } + #endregion methods + } + + /// + /// Implements the visitor pattern based on the interface + /// to convert the content of a object into a + /// object. + /// + sealed class TranslateElementVisitor : IXshtdVisitor + { + #region fields + readonly XmlHighlightingThemeDefinition def; + #endregion fields + + #region ctors + /// + /// Class constructor. + /// + /// + /// + public TranslateElementVisitor(XmlHighlightingThemeDefinition def, + IHighlightingThemeDefinitionReferenceResolver resolver) + { + Debug.Assert(def != null); + Debug.Assert(resolver != null); + this.def = def; + } + #endregion ctors + + #region methods + /// + /// Implements the visitor for the object. + /// + /// + /// + public object VisitSyntaxDefinition(XshtdSyntaxDefinition syntax) + { + SyntaxDefinition c; + if (syntax.Name != null) + c = def.syntaxDefDict[syntax.Name]; + else + { + if (syntax.Extensions == null) + return null; + else + c = new SyntaxDefinition(syntax.Name); + } + + // Copy extensions to highlighting theme object + foreach (var item in syntax.Extensions) + c.Extensions.Add(item); + + syntax.AcceptElements(this); + + return c; + } + + /// + /// Implements the visitor for a named color ( object) + /// that is contained in a object. + /// + /// + /// + /// + public object VisitColor(XshtdSyntaxDefinition syntax, XshtdColor color) + { + if (color.Name == null) + throw Error(color, "Name must not be null"); + + if (color.Name.Length == 0) + throw Error(color, "Name must not be the empty string"); + + if (syntax == null) + throw Error(syntax, "Syntax Definition for theme must not be null"); + + SyntaxDefinition synDef; + HighlightingColor highColor; + if (def.syntaxDefDict.TryGetValue(syntax.Name, out synDef) == false) + throw Error(syntax, "Themed Syntax Definition does not exist '" + syntax.Name + "'."); + + highColor = synDef.ColorGet(color.Name); + if (highColor == null) + { + highColor = new HighlightingColor() { Name = color.Name }; + synDef.ColorAdd(highColor); + } + + highColor.Foreground = color.Foreground; + highColor.Background = color.Background; + highColor.Underline = color.Underline; + highColor.FontStyle = color.FontStyle; + highColor.FontWeight = color.FontWeight; + + return highColor; + } + + /// + /// Implements the visitor for the object. + /// + /// the element to be visited. + /// + public object VisitGlobalStyles(XshtdGlobalStyles globStyles) + { + globStyles.AcceptElements(this); + + return null; + } + + public object VisitGlobalStyle(XshtdGlobalStyles globStyles, XshtdGlobalStyle style) + { + if (style.TypeName == null) + throw Error(style, "Name must not be null"); + + if (style.TypeName.Length == 0) + throw Error(style, "Name must not be the empty string"); + + if (globStyles == null) + throw Error(globStyles, "GlobalStyles parameter must not be null"); + + GlobalStyle globDef; + if (def._GlobalStyles.TryGetValue(style.TypeName, out globDef) == false) + throw Error(style, "Style definition '" + style.TypeName + "' does not exist in collection of GlobalStyles."); + + globDef.backgroundcolor = style.background; + globDef.foregroundcolor = style.foreground; + globDef.bordercolor = style.bordercolor; + globDef.Freeze(); + + return globDef; + } + #endregion methods + } + #endregion private classes + } +} diff --git a/src/HL/Xshtd/XshtdColor.cs b/src/HL/Xshtd/XshtdColor.cs new file mode 100644 index 0000000..0975690 --- /dev/null +++ b/src/HL/Xshtd/XshtdColor.cs @@ -0,0 +1,158 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd +{ + using ICSharpCode.AvalonEdit.Highlighting; + using System; + using System.Runtime.Serialization; + using System.Security.Permissions; + using System.Windows; + + /// + /// A color in an Xshd file. + /// + [Serializable] + public class XshtdColor : XshtdElement, ISerializable + { + #region fields + private readonly XshtdSyntaxDefinition _syntax; + #endregion fields + + #region ctors + /// + /// Creates a new XshdColor instance that is part of a . + /// + public XshtdColor(XshtdSyntaxDefinition syntax) + { + _syntax = syntax; + } + + /// + /// Deserializes an XshdColor. + /// + protected XshtdColor(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + + this.Name = info.GetString("Name"); + this.Foreground = (HighlightingBrush)info.GetValue("Foreground", typeof(HighlightingBrush)); + this.Background = (HighlightingBrush)info.GetValue("Background", typeof(HighlightingBrush)); + + if (info.GetBoolean("HasWeight")) + this.FontWeight = System.Windows.FontWeight.FromOpenTypeWeight(info.GetInt32("Weight")); + + if (info.GetBoolean("HasStyle")) + this.FontStyle = (FontStyle?)new FontStyleConverter().ConvertFromInvariantString(info.GetString("Style")); + + this.ExampleText = info.GetString("ExampleText"); + + if (info.GetBoolean("HasUnderline")) + this.Underline = info.GetBoolean("Underline"); + } + #endregion ctors + + #region properties + /// + /// Gets/sets the name. + /// + public string Name { get; set; } + + /// + /// Gets/sets the foreground brush. + /// + public HighlightingBrush Foreground { get; set; } + + /// + /// Gets/sets the background brush. + /// + public HighlightingBrush Background { get; set; } + + /// + /// Gets/sets the font weight. + /// + public FontWeight? FontWeight { get; set; } + + /// + /// Gets/sets the underline flag + /// + public bool? Underline { get; set; } + + /// + /// Gets/sets the font style. + /// + public FontStyle? FontStyle { get; set; } + + /// + /// Gets/Sets the example text that demonstrates where the color is used. + /// + public string ExampleText { get; set; } + #endregion properties + + /// + /// Serializes this XshdColor instance. + /// +#if DOTNET4 + [System.Security.SecurityCritical] +#else + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] +#endif + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + if (info == null) + throw new ArgumentNullException("info"); + + info.AddValue("Name", this.Name); + info.AddValue("Foreground", this.Foreground); + info.AddValue("Background", this.Background); + info.AddValue("HasUnderline", this.Underline.HasValue); + + if (this.Underline.HasValue) + info.AddValue("Underline", this.Underline.Value); + + info.AddValue("HasWeight", this.FontWeight.HasValue); + + if (this.FontWeight.HasValue) + info.AddValue("Weight", this.FontWeight.Value.ToOpenTypeWeight()); + + info.AddValue("HasStyle", this.FontStyle.HasValue); + + if (this.FontStyle.HasValue) + info.AddValue("Style", this.FontStyle.Value.ToString()); + + info.AddValue("ExampleText", this.ExampleText); + } + + /// + /// Applies the visitor to this element. + /// + /// + /// + public override object AcceptVisitor(IXshtdVisitor visitor) + { + return visitor.VisitColor(_syntax, this); + } + } +} diff --git a/src/HL/Xshtd/XshtdElement.cs b/src/HL/Xshtd/XshtdElement.cs new file mode 100644 index 0000000..599ac93 --- /dev/null +++ b/src/HL/Xshtd/XshtdElement.cs @@ -0,0 +1,50 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd +{ + using System; + + /// + /// An element in a XSHD rule set. + /// + [Serializable] + public abstract class XshtdElement + { + /// + /// Gets the line number in the .xshd file. + /// + public int LineNumber { get; set; } + + /// + /// Gets the column number in the .xshd file. + /// + public int ColumnNumber { get; set; } + + /// + /// Applies the visitor to this element. + /// + public abstract object AcceptVisitor(IXshtdVisitor visitor); + } +} diff --git a/src/HL/Xshtd/XshtdGlobalStyle.cs b/src/HL/Xshtd/XshtdGlobalStyle.cs new file mode 100644 index 0000000..dd174da --- /dev/null +++ b/src/HL/Xshtd/XshtdGlobalStyle.cs @@ -0,0 +1,75 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Xshtd +{ + using System; + using System.Windows.Media; + + /// + /// An element contained in a <GlobalStyles> element. + /// + [Serializable] + public class XshtdGlobalStyle : XshtdElement + { + #region fields + private readonly XshtdGlobalStyles _styles; + #endregion fields + + #region ctors + /// + /// Creates a new XshtdSyntaxDefinition object. + /// + /// Parent collection of styles in which this style occurs. + public XshtdGlobalStyle(XshtdGlobalStyles styles) + : this() + { + _styles = styles; + } + + /// + /// Hidden class constructor + /// + protected XshtdGlobalStyle() + { + } + #endregion ctors + + /// + /// Gets/sets the style definition name + /// + public string TypeName { get; set; } + + /// + /// Gets/sets the style definition name + /// + public Color? foreground { get; set; } + + /// + /// Gets/sets the style definition name + /// + public Color? background { get; set; } + + /// + /// Gets/sets the style definition name + /// + public Color? bordercolor { get; set; } + + #region methods + + /// + /// Applies the visitor to this element. + /// + /// + /// + public override object AcceptVisitor(IXshtdVisitor visitor) + { + return visitor.VisitGlobalStyle(_styles, this); + } + #endregion methods + } +} diff --git a/src/HL/Xshtd/XshtdGlobalStyles.cs b/src/HL/Xshtd/XshtdGlobalStyles.cs new file mode 100644 index 0000000..ae7c247 --- /dev/null +++ b/src/HL/Xshtd/XshtdGlobalStyles.cs @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Xshtd +{ + using System; + using System.Collections.Generic; + using ICSharpCode.AvalonEdit.Utils; + + /// + /// A <GlobalStyles> element. + /// + [Serializable] + public class XshtdGlobalStyles : XshtdElement + { + /// + /// Creates a new XshtdSyntaxDefinition object. + /// + public XshtdGlobalStyles() + { + this.Elements = new NullSafeCollection(); + } + + /// + /// Gets the collection of elements. + /// + public IList Elements { get; private set; } + + /// + /// Applies the visitor to all elements. + /// + public void AcceptElements(IXshtdVisitor visitor) + { + foreach (XshtdElement element in Elements) + { + element.AcceptVisitor(visitor); + } + } + + /// + /// Applies the visitor to this element. + /// + /// + /// + public override object AcceptVisitor(IXshtdVisitor visitor) + { + return visitor.VisitGlobalStyles(this); + } + } +} diff --git a/src/HL/Xshtd/XshtdSyntaxDefinition.cs b/src/HL/Xshtd/XshtdSyntaxDefinition.cs new file mode 100644 index 0000000..a6eddbb --- /dev/null +++ b/src/HL/Xshtd/XshtdSyntaxDefinition.cs @@ -0,0 +1,82 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd +{ + using System; + using System.Collections.Generic; + using ICSharpCode.AvalonEdit.Utils; + + /// + /// A <SyntaxDefinition> Xml element. + /// + [Serializable] + public class XshtdSyntaxDefinition : XshtdElement + { + /// + /// Creates a new XshtdSyntaxDefinition object. + /// + public XshtdSyntaxDefinition() + { + this.Elements = new NullSafeCollection(); + this.Extensions = new NullSafeCollection(); + } + + /// + /// Gets/sets the definition name + /// + public string Name { get; set; } + + /// + /// Gets the associated extensions. + /// + public IList Extensions { get; private set; } + + /// + /// Gets the collection of elements. + /// + public IList Elements { get; private set; } + + /// + /// Applies the visitor to all elements. + /// + public void AcceptElements(IXshtdVisitor visitor) + { + foreach (XshtdElement element in Elements) + { + element.AcceptVisitor(visitor); + } + } + + /// + /// Applies the visitor to this element. + /// + /// + /// + public override object AcceptVisitor(IXshtdVisitor visitor) + { + return visitor.VisitSyntaxDefinition(this); + } + } +} diff --git a/src/HL/Xshtd/interfaces/IFreezable.cs b/src/HL/Xshtd/interfaces/IFreezable.cs new file mode 100644 index 0000000..f6e88dc --- /dev/null +++ b/src/HL/Xshtd/interfaces/IFreezable.cs @@ -0,0 +1,153 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +namespace HL.Xshtd.interfaces +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + + /// + /// Defines a freezable base for all objects that should be freezable. + /// Frozen instances are immutable and thus thread-safe. + /// + interface IFreezable + { + /// + /// Gets if this instance is frozen. Frozen instances are immutable and thus thread-safe. + /// + bool IsFrozen { get; } + + /// + /// Freezes this instance. + /// + void Freeze(); + } + + static class FreezableHelper + { + public static void ThrowIfFrozen(IFreezable freezable) + { + if (freezable.IsFrozen) + throw new InvalidOperationException("Cannot mutate frozen " + freezable.GetType().Name); + } + + public static IList FreezeListAndElements(IList list) + { + if (list != null) + { + foreach (T item in list) + Freeze(item); + } + + return FreezeList(list); + } + + public static IList FreezeList(IList list) + { + if (list == null || list.Count == 0) + return new T[0]; + + if (list.IsReadOnly) + { + // If the list is already read-only, return it directly. + // This is important, otherwise we might undo the effects of interning. + return list; + } + else + { + return new ReadOnlyCollection(list.ToArray()); + } + } + + public static void Freeze(object item) + { + IFreezable f = item as IFreezable; + + if (f != null) + f.Freeze(); + } + + public static T FreezeAndReturn(T item) where T : IFreezable + { + item.Freeze(); + + return item; + } + + /// + /// If the item is not frozen, this method creates and returns a frozen clone. + /// If the item is already frozen, it is returned without creating a clone. + /// + public static T GetFrozenClone(T item) where T : IFreezable, ICloneable + { + if (!item.IsFrozen) + { + item = (T)item.Clone(); + item.Freeze(); + } + + return item; + } + } + + /// + /// Implements a freezable base for all objects that should be freezable. + /// Frozen instances are immutable and thus thread-safe. + /// + [Serializable] + public abstract class AbstractFreezable : IFreezable + { + private bool isFrozen; + + /// + /// Gets if this instance is frozen. Frozen instances are immutable and thus thread-safe. + /// + public bool IsFrozen + { + get { return isFrozen; } + } + + /// + /// Freezes this instance. + /// + public void Freeze() + { + if (!isFrozen) + { + FreezeInternal(); + isFrozen = true; + } + } + + /// + /// Provides a way of freezing additional elements defined in inheriting + /// classes through the invocation of the method. + /// + protected virtual void FreezeInternal() + { + } + } +} \ No newline at end of file diff --git a/src/HL/Xshtd/interfaces/IHighlightingDefinitionReferenceResolver.cs b/src/HL/Xshtd/interfaces/IHighlightingDefinitionReferenceResolver.cs new file mode 100644 index 0000000..0ab8d7b --- /dev/null +++ b/src/HL/Xshtd/interfaces/IHighlightingDefinitionReferenceResolver.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Xshtd.interfaces +{ + using HL.HighlightingTheme; + + /// + /// Defines a resolver interface that can find highlighting theme definitions + /// based on a highlighting name (searches within the current highlighting theme) + /// or based on a highlighting name and name of highlighting theme that should + /// contain the highlighting definition. + /// + public interface IHighlightingThemeDefinitionReferenceResolver + { + /// + /// Gets a highlighting definition within the current highlighting theme + /// by name, or null. + /// + /// + /// + SyntaxDefinition GetThemeDefinition(string highlightingName); + + /// + /// Gets a highlighting theme definition by name from a given highlighting + /// theme obtained via or null. + /// + /// + /// + SyntaxDefinition GetThemeDefinition(string hlThemeName, + string highlightingName); + } +} diff --git a/src/HL/Xshtd/interfaces/IHighlightingThemeDefinition.cs b/src/HL/Xshtd/interfaces/IHighlightingThemeDefinition.cs new file mode 100644 index 0000000..77c7869 --- /dev/null +++ b/src/HL/Xshtd/interfaces/IHighlightingThemeDefinition.cs @@ -0,0 +1,35 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace HL.Xshtd.interfaces +{ + using HL.HighlightingTheme; + using System.Collections.Generic; + + /// + /// A highlighting definition. + /// + public interface IHighlightingThemeDefinition + { + /// + /// Gets the name of the highlighting theme definition. + /// + string Name { get; } + + /// + /// Gets a named highlighting color. + /// + /// The highlighting color, or null if it is not found. + ////HighlightingColor GetNamedColor(string name); + SyntaxDefinition GetNamedSyntaxDefinition(string name); + + /// + /// Gets all global stayles in the collection of global styles. + /// + IEnumerable GlobalStyles { get; } + } +} diff --git a/src/HL/images/icon.png b/src/HL/images/icon.png new file mode 100644 index 0000000..6fdbdd3 Binary files /dev/null and b/src/HL/images/icon.png differ diff --git a/src/SimpleVersionControl.App.Installer/Product.wxs b/src/SimpleVersionControl.App.Installer/Product.wxs new file mode 100644 index 0000000..2165b59 --- /dev/null +++ b/src/SimpleVersionControl.App.Installer/Product.wxs @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SimpleVersionControl.App.Installer/StartMenuManager.GUI.Installer.wixproj b/src/SimpleVersionControl.App.Installer/StartMenuManager.GUI.Installer.wixproj new file mode 100644 index 0000000..6bd3b3b --- /dev/null +++ b/src/SimpleVersionControl.App.Installer/StartMenuManager.GUI.Installer.wixproj @@ -0,0 +1,58 @@ + + + + Debug + x86 + 3.10 + b7cbb2b3-65e2-44fb-aad6-9bd76884d09d + 2.0 + StartMenuManager.GUI.Installer + Package + + + bin\$(Configuration)\ + obj\$(Configuration)\ + Debug + + + bin\$(Configuration)\ + obj\$(Configuration)\ + + + + + + + + SimpleVersionControl.App + {94fb3269-cc7c-4412-a35e-6fadf9431b40} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + + + $(WixExtDir)\WixUtilExtension.dll + WixUtilExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl.App.Installer/netchecker.wxs b/src/SimpleVersionControl.App.Installer/netchecker.wxs new file mode 100644 index 0000000..3487d76 --- /dev/null +++ b/src/SimpleVersionControl.App.Installer/netchecker.wxs @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + WIXNETFX4RELEASEINSTALLED >= "#$(var.NetFx472MinRelease)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl.App/App.config b/src/SimpleVersionControl.App/App.config new file mode 100644 index 0000000..8d23437 --- /dev/null +++ b/src/SimpleVersionControl.App/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/SimpleVersionControl.App/App.xaml b/src/SimpleVersionControl.App/App.xaml new file mode 100644 index 0000000..805c44f --- /dev/null +++ b/src/SimpleVersionControl.App/App.xaml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/src/SimpleVersionControl.App/App.xaml.cs b/src/SimpleVersionControl.App/App.xaml.cs new file mode 100644 index 0000000..7724328 --- /dev/null +++ b/src/SimpleVersionControl.App/App.xaml.cs @@ -0,0 +1,16 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; + +namespace CustomWindow +{ + /// + /// App Class + /// + public partial class App : Application + { + } +} diff --git a/src/SimpleVersionControl.App/MainWindow.xaml b/src/SimpleVersionControl.App/MainWindow.xaml new file mode 100644 index 0000000..829b988 --- /dev/null +++ b/src/SimpleVersionControl.App/MainWindow.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/src/SimpleVersionControl.App/MainWindow.xaml.cs b/src/SimpleVersionControl.App/MainWindow.xaml.cs new file mode 100644 index 0000000..00b2d92 --- /dev/null +++ b/src/SimpleVersionControl.App/MainWindow.xaml.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; + +namespace SimpleVersionControl.App +{ + /// + /// MainWindow + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + + LocationChanged += TitleBar.Window_LocationChanged; + StateChanged += TitleBar.Window_StateChanged; + } + + public VersionController VersionController { get; set; } + + public static MainWindow GetInstance() + { + return (MainWindow)Application.Current.MainWindow; + } + } +} diff --git a/src/SimpleVersionControl.App/Properties/AssemblyInfo.cs b/src/SimpleVersionControl.App/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7eb6904 --- /dev/null +++ b/src/SimpleVersionControl.App/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; + +[assembly: AssemblyTitle("SimpleVersionControl.App")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleVersionControl.App")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/SimpleVersionControl.App/Properties/Resources.Designer.cs b/src/SimpleVersionControl.App/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5f394e2 --- /dev/null +++ b/src/SimpleVersionControl.App/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SimpleVersionControl.App.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimpleVersionControl.App.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/src/SimpleVersionControl.App/Properties/Resources.resx b/src/SimpleVersionControl.App/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/src/SimpleVersionControl.App/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/SimpleVersionControl.App/Properties/Settings.Designer.cs b/src/SimpleVersionControl.App/Properties/Settings.Designer.cs new file mode 100644 index 0000000..1d9de6b --- /dev/null +++ b/src/SimpleVersionControl.App/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SimpleVersionControl.App.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/src/SimpleVersionControl.App/Properties/Settings.settings b/src/SimpleVersionControl.App/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/src/SimpleVersionControl.App/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl.App/SimpleVersionControl.App.csproj b/src/SimpleVersionControl.App/SimpleVersionControl.App.csproj new file mode 100644 index 0000000..e314c5f --- /dev/null +++ b/src/SimpleVersionControl.App/SimpleVersionControl.App.csproj @@ -0,0 +1,188 @@ + + + + + Debug + AnyCPU + {94FB3269-CC7C-4412-A35E-6FADF9431B40} + WinExe + SimpleVersionControl.App + SimpleVersionControl.App + v4.6.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + icon-256x256.ico + + + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + ContentArea.xaml + + + VersionControl.xaml + + + ChangeLogPage.xaml + + + ChangePage.xaml + + + NothingOpenPage.xaml + + + VersionPage.xaml + + + ChangeControl.xaml + + + TitleBar.xaml + + + FileMenu.xaml + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {26FDCA06-B4D8-4D43-AD29-1EA0B6B2E2F4} + HL + + + {0df4934a-83b0-4ee2-9486-892f6b22648c} + SimpleVersionControl + + + {5ad36454-7653-4282-9b9f-2183f0064754} + TextEditLib + + + + + 3.1.3 + + + + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl.App/UserControls/ContentArea.xaml b/src/SimpleVersionControl.App/UserControls/ContentArea.xaml new file mode 100644 index 0000000..6c503d3 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentArea.xaml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentArea.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentArea.xaml.cs new file mode 100644 index 0000000..c817fec --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentArea.xaml.cs @@ -0,0 +1,131 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; + +namespace SimpleVersionControl.App.UserControls +{ + /// + /// Interaction logic for ContentArea.xaml + /// + public partial class ContentArea : UserControl + { + public ContentArea() + { + InitializeComponent(); + } + + public enum PageType + { + Empty, + ChangeLog, + Version, + Change, + } + + public static ContentArea GetInstance() + { + return MainWindow.GetInstance().ContentArea; + } + + public void OpenPage(PageType pageType, VersionRef versionRef = null, ChangeRef changeRef = null) + { + EmptyPage.Visibility = Visibility.Collapsed; + ChangeLogPage.Visibility = Visibility.Collapsed; + VersionPage.Visibility = Visibility.Collapsed; + ChangePage.Visibility = Visibility.Collapsed; + + switch (pageType) + { + case PageType.Empty: + EmptyPage.Visibility = Visibility.Visible; + break; + case PageType.ChangeLog: + ChangeLogPage.Visibility = Visibility.Visible; + ChangeLogPage.Refresh(); + break; + case PageType.Version: + if (versionRef == null) + { + return; + } + + VersionPage.Visibility = Visibility.Visible; + VersionPage.Refresh(versionRef); + break; + case PageType.Change: + if (changeRef == null) + { + return; + } + + ChangePage.Visibility = Visibility.Visible; + ChangePage.Refresh(changeRef); + break; + } + } + + public async Task PostSerializeReload(VersionController versionController) + { + ChangeLog changeLog = await versionController.GetChangeLog(); + + if (EmptyPage.Visibility == Visibility.Visible) + { + return; + } + + if (ChangeLogPage.Visibility == Visibility.Visible) + { + OpenPage(PageType.ChangeLog); + return; + } + + if (VersionPage.Visibility == Visibility.Visible) + { + VersionRef oldRef = VersionPage.GetRef(); + foreach (VersionRef versionRef in changeLog.Versions) + { + if (versionRef.VersionName == oldRef.VersionName) + { + OpenPage(PageType.Version, versionRef); + return; + } + } + + OpenPage(PageType.ChangeLog); + return; + } + + if (ChangePage.Visibility == Visibility.Visible) + { + VersionRef oldVersionRef = VersionPage.GetRef(); + ChangeRef oldChangeRef = ChangePage.GetChangeRef(); + foreach (VersionRef versionRef in changeLog.Versions) + { + if (versionRef.VersionName == oldVersionRef.VersionName) + { + Version version = await versionRef.GetVersion(); + foreach (ChangeRef changeRef in version.Changes) + { + if (changeRef.Guid == oldChangeRef.Guid) + { + OpenPage(PageType.Change, versionRef, changeRef); + return; + } + } + + OpenPage(PageType.Version, versionRef); + return; + } + } + + OpenPage(PageType.ChangeLog); + return; + } + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml new file mode 100644 index 0000000..2920a1d --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + Version: 1.0.0 + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml.cs new file mode 100644 index 0000000..5cffc8f --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogControls/VersionControl.xaml.cs @@ -0,0 +1,48 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; +using System.Windows.Controls; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls.ChangeLogControls +{ + /// + /// Interaction logic for VersionControl.xaml + /// + public partial class VersionControl : UserControl + { + public VersionControl(VersionRef versionRef) + { + InitializeComponent(); + + VersionText.Text = versionRef.VersionName; + } + + public void EditPressed(object sender, RoutedEventArgs args) + { + ChangeLogPage.GetInstance().Edit(this); + } + + public void MoveUpPressed(object sender, RoutedEventArgs args) + { + ChangeLogPage.GetInstance().MoveUp(this); + } + + public void MoveDownPressed(object sender, RoutedEventArgs args) + { + ChangeLogPage.GetInstance().MoveDown(this); + } + + public void DuplicatePressed(object sender, RoutedEventArgs args) + { + ChangeLogPage.GetInstance().Duplicate(this); + } + + public void DeletePressed(object sender, RoutedEventArgs args) + { + ChangeLogPage.GetInstance().Delete(this); + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml new file mode 100644 index 0000000..4bb493e --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml @@ -0,0 +1,59 @@ + + + + + + + + + Additional ChangeLog Data + + + + + Add any additional fields to be stored in the ChangeLog as JSON code below: + + Error: The text you've entered is not valid JSON! + + + + + + + + + Add Application Versions to the ChangeLog below: + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml.cs new file mode 100644 index 0000000..718a3d8 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangeLogPage.xaml.cs @@ -0,0 +1,266 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using CustomWindow; +using HL.Interfaces; +using HL.Manager; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SimpleVersionControl.App.UserControls.ContentAreaControls.ChangeLogControls; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls +{ + /// + /// Interaction logic for ChagneLogPage.xaml + /// + public partial class ChangeLogPage : UserControl + { + private bool eventBlock = false; + + public ChangeLogPage() + { + InitializeComponent(); + + IThemedHighlightingManager hm = ThemedHighlightingManager.Instance; + hm.SetCurrentTheme("VS2019_Dark"); + AdditionalDataField.SyntaxHighlighting = hm.GetDefinitionByExtension(".js"); + } + + public static ChangeLogPage GetInstance() + { + return ContentArea.GetInstance().ChangeLogPage; + } + + public async void Refresh() + { + AdditionalDataExpander.IsExpanded = false; + + ChangeLog changeLog = await MainWindow.GetInstance().VersionController.GetChangeLog(); + if (changeLog == null) + { + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Empty); + MainWindow.GetInstance().VersionController = null; + return; + } + + if (changeLog.AdditionalData == null) + { + changeLog.AdditionalData = JObject.Parse("{}"); + } + + eventBlock = true; + AdditionalDataField.Text = changeLog.AdditionalData.ToString(Formatting.Indented); + + VersionParent.Children.Clear(); + + foreach (VersionRef versionRef in changeLog.Versions) + { + VersionControl versionControl = new VersionControl(versionRef); + VersionParent.Children.Add(versionControl); + } + } + + private async void AdditionalDataField_TextChanged(object sender, System.EventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + ChangeLog changeLog = await MainWindow.GetInstance().VersionController.GetChangeLog(); + + try + { + JObject newObject = JObject.Parse(AdditionalDataField.Text); + changeLog.AdditionalData = newObject; + JsonErrorText.Visibility = System.Windows.Visibility.Collapsed; + } + catch (Exception) + { + JsonErrorText.Visibility = System.Windows.Visibility.Visible; + } + } + + public bool IsJsonValid() + { + return JsonErrorText.Visibility != System.Windows.Visibility.Visible; + } + + public void CreateVersionPressed(object sender, RoutedEventArgs args) + { + VersionController versionController = MainWindow.GetInstance().VersionController; + string newVersionName = GetNewVersionName(); + VersionRef versionRef = new VersionRef(versionController, Path.Combine(newVersionName, "version.json"), newVersionName); + VersionControl newControl = new VersionControl(versionRef); + VersionParent.Children.Insert(0, newControl); + ChangeLog changeLog = versionController.GetChangeLog().Result; + changeLog.Versions.Insert(0, versionRef); + + Version version = new Version(versionController, newVersionName, string.Empty, string.Empty, DateTime.Now, new System.Collections.Generic.List()); + versionController.CacheVersion(version); + + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Version, versionRef); + } + + public void Edit(VersionControl control) + { + int index = VersionParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Version, changeLog.Versions[index]); + } + + public void MoveUp(VersionControl control) + { + int index = VersionParent.Children.IndexOf(control); + + if (index <= 0) + { + return; + } + + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + + VersionRef versionRef = changeLog.Versions[index]; + changeLog.Versions.Remove(versionRef); + VersionParent.Children.Remove(control); + + changeLog.Versions.Insert(index - 1, versionRef); + VersionParent.Children.Insert(index - 1, control); + } + + public void MoveDown(VersionControl control) + { + int index = VersionParent.Children.IndexOf(control); + + if (index == -1 || index == VersionParent.Children.Count - 1) + { + return; + } + + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + VersionRef versionRef = changeLog.Versions[index]; + changeLog.Versions.Remove(versionRef); + VersionParent.Children.Remove(control); + + changeLog.Versions.Insert(index + 1, versionRef); + VersionParent.Children.Insert(index + 1, control); + } + + public void Duplicate(VersionControl control) + { + int index = VersionParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + VersionController versionController = MainWindow.GetInstance().VersionController; + ChangeLog changeLog = versionController.GetChangeLog().Result; + VersionRef oldVersionRef = changeLog.Versions[index]; + string duplicateName = GetDuplicateName(oldVersionRef.VersionName); + VersionRef newVersionRef = new VersionRef(versionController, oldVersionRef.RelativeFilePath, duplicateName); + changeLog.Versions.Insert(index + 1, newVersionRef); + VersionControl newControl = new VersionControl(newVersionRef); + VersionParent.Children.Insert(index + 1, newControl); + + Version oldVersion = oldVersionRef.GetVersion(false).Result; + Version version = new Version(versionController, duplicateName, oldVersion.Description, oldVersion.DownloadLink, oldVersion.ReleaseDate, new System.Collections.Generic.List()); + if (oldVersion.AdditionalData != null) + { + version.AdditionalData = (JObject)oldVersion.AdditionalData.DeepClone(); + } + + foreach (ChangeRef oldChangeRef in oldVersion.Changes) + { + string guid = Guid.NewGuid().ToString(); + string newChangePath = Path.Combine(version.VersionName, "changes", $"{guid}.json"); + ChangeRef newChangeRef = new ChangeRef(versionController, guid, newChangePath); + Change oldChange = oldChangeRef.GetChange(false).Result; + Change newChange = new Change(versionController, guid, newChangePath, oldChange.Title, oldChange.Description, newVersionRef); + if (oldChange.ReleaseVersion != null) + { + newChange.ReleaseVersion = new VersionRef(versionController, newVersionRef.RelativeFilePath, newVersionRef.VersionName); + } + + if (oldChange.AdditionalData != null) + { + newChange.AdditionalData = (JObject)oldChange.AdditionalData.DeepClone(); + } + + version.Changes.Add(newChangeRef); + versionController.CacheChange(newChange); + } + + versionController.CacheVersion(version); + } + + public void Delete(VersionControl control) + { + int index = VersionParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + VersionParent.Children.Remove(control); + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + changeLog.Versions.RemoveAt(index); + } + + private string GetDuplicateName(string baseName) + { + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + + // Check adding " Copy" + if (changeLog.Versions.FirstOrDefault(v => v.VersionName == $"{baseName} Copy") == null) + { + return $"{baseName} Copy"; + } + + // Check adding " Copy 2", " Copy 3", ... etc + int index = 2; + while (changeLog.Versions.FirstOrDefault(v => v.VersionName == $"{baseName} Copy {index}") != null) + { + index++; + } + + return $"{baseName} Copy {index}"; + } + + private string GetNewVersionName() + { + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + + // Try "New Version" + if (changeLog.Versions.FirstOrDefault(v => v.VersionName == "New Version") == null) + { + return $"New Version"; + } + + // Try "New Version 2", "New Version 3", ... etc + int index = 2; + while (changeLog.Versions.FirstOrDefault(v => v.VersionName == $"New Version {index}") != null) + { + index++; + } + + return $"New Version {index}"; + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml new file mode 100644 index 0000000..3aa1fe3 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml @@ -0,0 +1,66 @@ + + + + + Version: 1.0.0 + + + + + + Added Some Feature + + + + + Description: + + + + + + + + + Additional Change Data + + + + + Add any additional fields to be stored in the Change as JSON code below: + + Error: The text you've entered is not valid JSON! + + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml.cs new file mode 100644 index 0000000..49c1831 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/ChangePage.xaml.cs @@ -0,0 +1,127 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Windows; +using System.Windows.Controls; +using HL.Interfaces; +using HL.Manager; +using Newtonsoft.Json.Linq; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls +{ + /// + /// Interaction logic for ChangePage.xaml + /// + public partial class ChangePage : UserControl + { + private bool eventBlock = false; + private ChangeRef openChangeRef; + private VersionRef versionRef; + + public ChangePage() + { + InitializeComponent(); + + IThemedHighlightingManager hm = ThemedHighlightingManager.Instance; + hm.SetCurrentTheme("VS2019_Dark"); + AdditionalDataField.SyntaxHighlighting = hm.GetDefinitionByExtension(".js"); + } + + public static ChangePage GetInstance() + { + return ContentArea.GetInstance().ChangePage; + } + + public void Refresh(ChangeRef changeRef) + { + AdditionalDataExpander.IsExpanded = false; + + openChangeRef = changeRef; + + Change change = changeRef.GetChange().Result; + versionRef = change.ReleaseVersion; + VersionText.Text = $"Version: {change.ReleaseVersion.VersionName}"; + + eventBlock = true; + ChangeTitleField.Text = change.Title; + + eventBlock = true; + DescriptionField.Text = change.Description; + + if (change.AdditionalData == null) + { + change.AdditionalData = JObject.Parse("{}"); + } + + eventBlock = true; + AdditionalDataField.Text = change.AdditionalData.ToString(Newtonsoft.Json.Formatting.Indented); + } + + public async void BackButtonPressed(object sender, RoutedEventArgs args) + { + Change change = await openChangeRef.GetChange(); + VersionRef versionRef = change.ReleaseVersion; + openChangeRef = null; + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Version, versionRef); + } + + private async void ChangeTitleField_TextChanged(object sender, TextChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Change change = await openChangeRef.GetChange(); + change.Title = ChangeTitleField.Text; + } + + private async void DescriptionField_TextChanged(object sender, TextChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Change change = await openChangeRef.GetChange(); + change.Description = DescriptionField.Text; + } + + private async void AdditionalDataField_TextChanged(object sender, System.EventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Change change = await openChangeRef.GetChange(); + + try + { + JObject newObject = JObject.Parse(AdditionalDataField.Text); + change.AdditionalData = newObject; + JsonErrorText.Visibility = System.Windows.Visibility.Collapsed; + } + catch (Exception) + { + JsonErrorText.Visibility = System.Windows.Visibility.Visible; + } + } + + internal ChangeRef GetChangeRef() + { + return openChangeRef; + } + + internal VersionRef GetVersionRef() + { + return versionRef; + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml new file mode 100644 index 0000000..4d19835 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml @@ -0,0 +1,19 @@ + + + + No changelog loaded. Select a `changelog.json` file to open or create a new one. + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml.cs new file mode 100644 index 0000000..f95c073 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/NothingOpenPage.xaml.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; +using System.Windows.Controls; +using SimpleVersionControl.App.UserControls.TitleBarControls; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls +{ + /// + /// Interaction logic for NothingOpenPage.xaml + /// + public partial class NothingOpenPage : UserControl + { + public NothingOpenPage() + { + InitializeComponent(); + } + + private void OpenButtonPressed(object sender, RoutedEventArgs args) + { + FileMenu.GetInstance().OpenButtonPressed(sender, args); + } + + private void NewButtonPressed(object sender, RoutedEventArgs args) + { + FileMenu.GetInstance().NewButtonPressed(sender, args); + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml new file mode 100644 index 0000000..b5f1cdf --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml @@ -0,0 +1,91 @@ + + + + + + + + Version: + + 1.0.0 + + + + + Description: + + + + Download Link: + + + + Release Date: + + + + Is Version Still Functioning? + + + + + + + + + Additional Version Data + + + + + Add any additional fields to be stored in the Version as JSON code below: + + Error: The text you've entered is not valid JSON! + + + + + + + + + Add Changes made in this version to the list below: + + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml.cs new file mode 100644 index 0000000..fb83618 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPage.xaml.cs @@ -0,0 +1,336 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using HL.Interfaces; +using HL.Manager; +using Newtonsoft.Json.Linq; +using SimpleVersionControl.App.UserControls.ContentAreaControls.VersionPageControls; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls +{ + /// + /// Interaction logic for VersionPage.xaml + /// + public partial class VersionPage : UserControl + { + private VersionRef openVersionRef; + private bool eventBlock = false; + private SolidColorBrush redColor; + private SolidColorBrush whiteColor; + + public VersionPage() + { + InitializeComponent(); + + redColor = new SolidColorBrush(Color.FromRgb(255, 0, 0)); + whiteColor = new SolidColorBrush(Color.FromRgb(255, 255, 255)); + + IThemedHighlightingManager hm = ThemedHighlightingManager.Instance; + hm.SetCurrentTheme("VS2019_Dark"); + AdditionalDataField.SyntaxHighlighting = hm.GetDefinitionByExtension(".js"); + } + + public static VersionPage GetInstance() + { + return ContentArea.GetInstance().VersionPage; + } + + public void Refresh(VersionRef versionRef) + { + AdditionalDataExpander.IsExpanded = false; + + openVersionRef = versionRef; + Version version = versionRef.GetVersion().Result; + + VersionField.Foreground = whiteColor; + VersionTitle.Foreground = whiteColor; + + AdditionalDataExpander.IsExpanded = false; + + eventBlock = true; + VersionField.Text = versionRef.VersionName; + + eventBlock = true; + DescriptionField.Text = version.Description; + + eventBlock = true; + LinkField.Text = version.DownloadLink; + + eventBlock = true; + ReleaseDateField.SelectedDate = version.ReleaseDate; + + if (FunctioningField.IsChecked == !version.IsFunctioning) + { + eventBlock = true; + FunctioningField.IsChecked = version.IsFunctioning; + } + + if (version.AdditionalData == null) + { + version.AdditionalData = JObject.Parse("{}"); + } + + eventBlock = true; + AdditionalDataField.Text = version.AdditionalData.ToString(Newtonsoft.Json.Formatting.Indented); + + ChangeParent.Children.Clear(); + + foreach (ChangeRef changeRef in version.Changes) + { + ChangeControl changeControl = new ChangeControl(changeRef); + ChangeParent.Children.Add(changeControl); + } + } + + public void BackButtonPressed(object sender, RoutedEventArgs args) + { + openVersionRef = null; + ContentArea.GetInstance().OpenPage(ContentArea.PageType.ChangeLog); + } + + private void NewChangeButtonPressed(object sender, RoutedEventArgs args) + { + Version version = openVersionRef.GetVersion().Result; + VersionController versionController = MainWindow.GetInstance().VersionController; + + string guid = Guid.NewGuid().ToString(); + string relativePath = Path.Combine(version.VersionName, "changes", $"{guid}.json"); + ChangeRef changeRef = new ChangeRef(versionController, guid, relativePath); + version.Changes.Insert(0, changeRef); + + Change change = new Change(versionController, guid, relativePath, "New Change", string.Empty, openVersionRef); + change.ReleaseVersion = new VersionRef(versionController, openVersionRef.RelativeFilePath, openVersionRef.VersionName); + versionController.CacheChange(change); + + ChangeControl newControl = new ChangeControl(changeRef); + ChangeParent.Children.Insert(0, newControl); + + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Change, openVersionRef, changeRef); + } + + public async void Edit(ChangeControl control) + { + int index = ChangeParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + Version version = await openVersionRef.GetVersion(); + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Change, openVersionRef, version.Changes[index]); + } + + public void Duplicate(ChangeControl control) + { + int index = ChangeParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + VersionController versionController = MainWindow.GetInstance().VersionController; + Version version = openVersionRef.GetVersion().Result; + ChangeRef oldChangeRef = version.Changes[index]; + string guid = Guid.NewGuid().ToString(); + string relativePath = Path.Combine(version.VersionName, "changes", $"{guid}.json"); + ChangeRef newChangeRef = new ChangeRef(versionController, guid, relativePath); + version.Changes.Insert(index + 1, newChangeRef); + + Change oldChange = oldChangeRef.GetChange(false).Result; + VersionRef releaseVersion = new VersionRef(versionController, oldChange.ReleaseVersion.RelativeFilePath, oldChange.ReleaseVersion.VersionName); + Change newChange = new Change(versionController, guid, relativePath, oldChange.Title, oldChange.Description, releaseVersion); + + if (oldChange.AdditionalData != null) + { + newChange.AdditionalData = (JObject)oldChange.AdditionalData.DeepClone(); + } + + versionController.CacheChange(newChange); + + ChangeControl newControl = new ChangeControl(newChangeRef); + ChangeParent.Children.Insert(index + 1, newControl); + } + + public void MoveUp(ChangeControl control) + { + int index = ChangeParent.Children.IndexOf(control); + + if (index <= 0) + { + return; + } + + Version version = openVersionRef.GetVersion().Result; + ChangeRef changeRef = version.Changes[index]; + version.Changes.Remove(changeRef); + ChangeParent.Children.Remove(control); + + version.Changes.Insert(index - 1, changeRef); + ChangeParent.Children.Insert(index - 1, control); + } + + public void MoveDown(ChangeControl control) + { + int index = ChangeParent.Children.IndexOf(control); + + if (index == -1 || index == ChangeParent.Children.Count - 1) + { + return; + } + + Version version = openVersionRef.GetVersion().Result; + ChangeRef changeRef = version.Changes[index]; + version.Changes.Remove(changeRef); + ChangeParent.Children.Remove(control); + + version.Changes.Insert(index + 1, changeRef); + ChangeParent.Children.Insert(index + 1, control); + } + + public void Delete(ChangeControl control) + { + int index = ChangeParent.Children.IndexOf(control); + + if (index == -1) + { + return; + } + + ChangeParent.Children.Remove(control); + Version version = openVersionRef.GetVersion().Result; + version.Changes.RemoveAt(index); + } + + private void VersionField_TextChanged(object sender, TextChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + ChangeLog changeLog = MainWindow.GetInstance().VersionController.GetChangeLog().Result; + bool versionAlreadyInUse = changeLog.Versions.FirstOrDefault(v => v != openVersionRef && v.VersionName == VersionField.Text) != null; + + if (versionAlreadyInUse) + { + VersionField.Foreground = redColor; + VersionTitle.Foreground = redColor; + return; + } + + VersionField.Foreground = whiteColor; + VersionTitle.Foreground = whiteColor; + + Version version = openVersionRef.GetVersion().Result; + version.VersionName = VersionField.Text; + + openVersionRef.VersionName = VersionField.Text; + openVersionRef.RelativeFilePath = Path.Combine(VersionField.Text, "version.json"); + + foreach (ChangeRef changeRef in version.Changes) + { + Change change = changeRef.GetChange().Result; + change.ReleaseVersion = openVersionRef; + changeRef.RelativeFilePath = Path.Combine(version.VersionName, "changes", $"{changeRef.Guid}.json"); + } + } + + private async void AdditionalDataField_TextChanged(object sender, System.EventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + + try + { + JObject newObject = JObject.Parse(AdditionalDataField.Text); + version.AdditionalData = newObject; + JsonErrorText.Visibility = System.Windows.Visibility.Collapsed; + } + catch (Exception) + { + JsonErrorText.Visibility = System.Windows.Visibility.Visible; + } + } + + private async void DescriptionField_TextChanged(object sender, TextChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + version.Description = DescriptionField.Text; + } + + private async void LinkField_TextChanged(object sender, TextChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + version.DownloadLink = LinkField.Text; + } + + private async void ReleaseDateField_SelectedDateChanged(object sender, SelectionChangedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + version.ReleaseDate = ReleaseDateField.SelectedDate.Value; + } + + private async void FunctioningField_Checked(object sender, RoutedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + version.IsFunctioning = true; + } + + private async void FunctioningField_Unchecked(object sender, RoutedEventArgs e) + { + if (eventBlock || MainWindow.GetInstance().VersionController == null) + { + eventBlock = false; + return; + } + + Version version = await openVersionRef.GetVersion(); + version.IsFunctioning = false; + } + + internal VersionRef GetRef() + { + return openVersionRef; + } + } +} \ No newline at end of file diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml new file mode 100644 index 0000000..8cae124 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + Something big changed + + + + diff --git a/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml.cs b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml.cs new file mode 100644 index 0000000..bbe991a --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/ContentAreaControls/VersionPageControls/ChangeControl.xaml.cs @@ -0,0 +1,48 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Windows; +using System.Windows.Controls; + +namespace SimpleVersionControl.App.UserControls.ContentAreaControls.VersionPageControls +{ + /// + /// Interaction logic for ChangeControl.xaml + /// + public partial class ChangeControl : UserControl + { + public ChangeControl(ChangeRef changeRef) + { + InitializeComponent(); + + ChangeTitle.Text = changeRef.GetChange(false).Result.Title; + } + + public void EditPressed(object sender, RoutedEventArgs args) + { + VersionPage.GetInstance().Edit(this); + } + + public void MoveUpPressed(object sender, RoutedEventArgs args) + { + VersionPage.GetInstance().MoveUp(this); + } + + public void MoveDownPressed(object sender, RoutedEventArgs args) + { + VersionPage.GetInstance().MoveDown(this); + } + + public void DuplicatePressed(object sender, RoutedEventArgs args) + { + VersionPage.GetInstance().Duplicate(this); + } + + public void DeletePressed(object sender, RoutedEventArgs args) + { + VersionPage.GetInstance().Delete(this); + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/TitleBar.xaml b/src/SimpleVersionControl.App/UserControls/TitleBar.xaml new file mode 100644 index 0000000..dbf5535 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/TitleBar.xaml @@ -0,0 +1,98 @@ + + + + + + + + + + Version Control App + + + + + + + + + + + + + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/TitleBar.xaml.cs b/src/SimpleVersionControl.App/UserControls/TitleBar.xaml.cs new file mode 100644 index 0000000..8522188 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/TitleBar.xaml.cs @@ -0,0 +1,141 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace SimpleVersionControl.App.UserControls +{ + /// + /// Interaction logic for TitleBar.xaml + /// + public partial class TitleBar : UserControl + { + private Point startPos; + private System.Windows.Forms.Screen[] screens = System.Windows.Forms.Screen.AllScreens; + + public TitleBar() + { + InitializeComponent(); + } + + [DllImport("user32.dll")] + private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); + + [DllImport("user32.dll")] + private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); + + [DllImport("user32.dll")] + private static extern int TrackPopupMenu(IntPtr hMenu, uint uFlags, int x, int y, int nReserved, IntPtr hWnd, IntPtr prcRect); + + public void Window_LocationChanged(object sender, EventArgs e) + { + MainWindow window = MainWindow.GetInstance(); + + int sum = 0; + foreach (var item in screens) + { + sum += item.WorkingArea.Width; + if (sum >= window.Left + (window.Width / 2)) + { + window.MaxHeight = item.WorkingArea.Height + 7; + break; + } + } + } + + private void System_MouseDown(object sender, MouseButtonEventArgs e) + { + MainWindow window = MainWindow.GetInstance(); + if (e.ChangedButton == MouseButton.Left) + { + if (e.ClickCount >= 2) + { + window.WindowState = (window.WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal; + } + else + { + startPos = e.GetPosition(null); + } + } + else if (e.ChangedButton == MouseButton.Right) + { + var pos = window.PointToScreen(e.GetPosition(window)); + IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(window).Handle; + IntPtr hMenu = GetSystemMenu(hWnd, false); + int cmd = TrackPopupMenu(hMenu, 0x100, (int)pos.X, (int)pos.Y, 0, hWnd, IntPtr.Zero); + if (cmd > 0) + { + SendMessage(hWnd, 0x112, (IntPtr)cmd, IntPtr.Zero); + } + } + } + + private void System_MouseMove(object sender, MouseEventArgs e) + { + MainWindow window = MainWindow.GetInstance(); + if (e.LeftButton == MouseButtonState.Pressed) + { + if (window.WindowState == WindowState.Maximized && Math.Abs(startPos.Y - e.GetPosition(null).Y) > 2) + { + var point = window.PointToScreen(e.GetPosition(null)); + + window.WindowState = WindowState.Normal; + + window.Left = point.X - (window.ActualWidth / 2); + window.Top = point.Y - (border.ActualHeight / 2); + } + + window.DragMove(); + } + } + + private void Maximize_Click(object sender, RoutedEventArgs e) + { + MainWindow.GetInstance().WindowState = (MainWindow.GetInstance().WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal; + } + + private void Close_Click(object sender, RoutedEventArgs e) + { + if (MainWindow.GetInstance().VersionController != null) + { + if (MessageBox.Show("Any unsaved changes will be lost.", "Are you sure you want to Exit?", MessageBoxButton.YesNo) == MessageBoxResult.No) + { + return; + } + } + + MainWindow.GetInstance().Close(); + } + + private void Mimimize_Click(object sender, RoutedEventArgs e) + { + MainWindow.GetInstance().WindowState = WindowState.Minimized; + } + + public void Window_StateChanged(object sender, EventArgs e) + { + MainWindow window = MainWindow.GetInstance(); + + if (window.WindowState == WindowState.Maximized) + { + window.main.BorderThickness = new Thickness(0); + window.main.Margin = new Thickness(7, 7, 7, 0); + rectMax.Visibility = Visibility.Hidden; + rectMin.Visibility = Visibility.Visible; + } + else + { + window.main.BorderThickness = new Thickness(1); + window.main.Margin = new Thickness(0); + rectMax.Visibility = Visibility.Visible; + rectMin.Visibility = Visibility.Hidden; + } + } + } +} diff --git a/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml b/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml new file mode 100644 index 0000000..7f24264 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml.cs b/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml.cs new file mode 100644 index 0000000..0276f30 --- /dev/null +++ b/src/SimpleVersionControl.App/UserControls/TitleBarControls/FileMenu.xaml.cs @@ -0,0 +1,190 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using Microsoft.Win32; +using SimpleVersionControl.App.UserControls.ContentAreaControls; + +namespace SimpleVersionControl.App.UserControls.TitleBarControls +{ + /// + /// Interaction logic for FileMenu.xaml + /// + public partial class FileMenu : UserControl + { + private Random random; + + public FileMenu() + { + InitializeComponent(); + } + + public static FileMenu GetInstance() + { + return MainWindow.GetInstance().TitleBar.FileMenu; + } + + public void OpenButtonPressed(object sender, RoutedEventArgs args) + { + if (MainWindow.GetInstance().VersionController != null) + { + if (MessageBox.Show("Any unsaved changes will be lost.", "Are you sure?", MessageBoxButton.YesNo) == MessageBoxResult.No) + { + return; + } + } + + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "ChangeLog Json File (changelog.json)|changelog.json"; + openFileDialog.InitialDirectory = Environment.SpecialFolder.Personal.ToString(); + if (openFileDialog.ShowDialog() == true) + { + if (!string.IsNullOrEmpty(openFileDialog.FileName)) + { + if (Path.GetFileName(openFileDialog.FileName) == "changelog.json" && File.Exists(openFileDialog.FileName)) + { + string dir = Path.GetDirectoryName(openFileDialog.FileName); + VersionController controller = new VersionController("0", new FileSystemProvider(dir)); + ChangeLog changeLog = controller.GetChangeLog().Result; + if (changeLog != null) + { + MainWindow.GetInstance().VersionController = controller; + ContentArea.GetInstance().OpenPage(ContentArea.PageType.ChangeLog); + return; + } + } + } + + MessageBox.Show("The selected file was not a valid 'changelog.json' file.", "Open ChangeLog Failed", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + public async void SaveButtonPressed(object sender, RoutedEventArgs args) + { + if (MainWindow.GetInstance().VersionController == null) + { + MessageBox.Show("No ChangeLog was open!", "Save Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // check json is correct in changelog + if (!ChangeLogPage.GetInstance().IsJsonValid()) + { + MessageBox.Show("The ChangeLog's additional data is not valid JSON.", "Save Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + try + { + bool seriallizeWorked = await MainWindow.GetInstance().VersionController.Serialize(); + if (!seriallizeWorked) + { + MessageBox.Show("Something went wrong.", "Save Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + OpenFolder(((FileSystemProvider)MainWindow.GetInstance().VersionController.FileProvider).RootPath); + } + catch (Exception e) + { + MessageBox.Show(e.Message, "Save Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + if (random == null) + { + random = new Random(); + } + + if (random.Next(5) == 1) + { + if (MessageBox.Show("It took a lot of work to make this available for free. If you have any money going spare, please consider donating to keep the project alive. Would you like to donate now?", "Please Consider Donating", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) + { + System.Diagnostics.Process.Start(@"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MLD56V6HQWCKU&source=url"); + } + } + + await ContentArea.GetInstance().PostSerializeReload(MainWindow.GetInstance().VersionController); + } + + public async void NewButtonPressed(object sender, RoutedEventArgs args) + { + if (MainWindow.GetInstance().VersionController != null) + { + if (MessageBox.Show("Any unsaved changes will be lost.", "Are you sure?", MessageBoxButton.YesNo) == MessageBoxResult.No) + { + return; + } + } + + using (var dialog = new System.Windows.Forms.FolderBrowserDialog()) + { + dialog.Description = "Pick Empty Directory to Store ChangeLog"; + System.Windows.Forms.DialogResult result = dialog.ShowDialog(); + if (result == System.Windows.Forms.DialogResult.OK) + { + if (!Directory.Exists(dialog.SelectedPath)) + { + MessageBox.Show("The selected directory could not be found.", "New ChangeLog Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + if (!IsDirectoryEmpty(dialog.SelectedPath)) + { + MessageBox.Show("The selected directory was not empty!", "New ChangeLog Failed", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + await CreateNewChangeLog(dialog.SelectedPath); + } + } + } + + private async Task CreateNewChangeLog(string path) + { + VersionController newVC = new VersionController("0", new FileSystemProvider(path)); + ChangeLog newCL = new ChangeLog(newVC, new List()); + MainWindow.GetInstance().VersionController = newVC; + bool seriallizeWorked = await newVC.Serialize(newCL); + if (!seriallizeWorked) + { + MessageBox.Show("The selected directory was not empty!", "New ChangeLog Failed", MessageBoxButton.OK, MessageBoxImage.Error); + ContentArea.GetInstance().OpenPage(ContentArea.PageType.Empty); + return; + } + + ContentArea.GetInstance().OpenPage(ContentArea.PageType.ChangeLog); + } + + private bool IsDirectoryEmpty(string path) + { + IEnumerable items = Directory.EnumerateFileSystemEntries(path); + using (IEnumerator en = items.GetEnumerator()) + { + return !en.MoveNext(); + } + } + + private void OpenFolder(string folderPath) + { + if (Directory.Exists(folderPath)) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + Arguments = folderPath, + FileName = "explorer.exe", + }; + + Process.Start(startInfo); + } + } + } +} diff --git a/src/SimpleVersionControl.App/icon-256x256.ico b/src/SimpleVersionControl.App/icon-256x256.ico new file mode 100644 index 0000000..32492ec Binary files /dev/null and b/src/SimpleVersionControl.App/icon-256x256.ico differ diff --git a/src/SimpleVersionControl.Example/App.config b/src/SimpleVersionControl.Example/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/src/SimpleVersionControl.Example/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl.Example/Program.cs b/src/SimpleVersionControl.Example/Program.cs new file mode 100644 index 0000000..28335ad --- /dev/null +++ b/src/SimpleVersionControl.Example/Program.cs @@ -0,0 +1,92 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +// For More Examples see the GitHub Readme + +using System; +using System.Threading.Tasks; + +namespace SimpleVersionControl.Example +{ + public class Program + { + public static int Main(string[] args) + { + // Needs to execute in async method + return MainAsync(args).Result; + } + + private static async Task MainAsync(string[] args) + { + string currentVersion = "1.0.0"; + string baseUrl = "https://start-menu-manager.jam-es.com/versions"; + + // Create instance of VersionController by passing in this version of the application, and the URL of the directory containing changelog file: + VersionController versionController = new VersionController(currentVersion, baseUrl); + Console.WriteLine($"This Version: {currentVersion}"); + + // Check this is the latest version + bool isLatestVersion = await versionController.IsLatestVersion(); + Console.WriteLine($"Is Latest Version: {isLatestVersion}"); + + // If not latest, you can check this version is still meant to function correctly + bool isFunctioningVersion = await versionController.IsFunctioningVersion(); + Console.WriteLine($"Is Version Functioning: {isFunctioningVersion}"); + + // The ChangeLog object contains a list of all versions that have been released + // We can list version properties like this: + ChangeLog changeLog = await versionController.GetChangeLog(); + Console.WriteLine(); + Console.WriteLine("All Versions:"); + foreach (VersionRef versionRef in changeLog.Versions) + { + Version version = await versionRef.GetVersion(); + Console.WriteLine($"Version Name: {version.VersionName}"); + Console.WriteLine($"Version Description: {version.Description}"); + Console.WriteLine($"Version Download Link: {version.DownloadLink}"); + Console.WriteLine($"Version Release Date: {version.ReleaseDate}"); + + // You can get all changes in a version with version.Changes + } + + // Get individual versions with: + VersionRef firstAppVersionRef = await versionController.GetFirstVersionRef(); + Version latestAppVersionRef = await versionController.GetLatestVersion(); + VersionRef specificVersionRef = await versionController.GetVersionRef("1.0.0b4"); + Console.WriteLine(); + Console.WriteLine($"First Version: {firstAppVersionRef.VersionName}"); + Console.WriteLine($"Latest Version: {latestAppVersionRef.VersionName}"); + Console.WriteLine($"Found Version 1.0.0b4: {specificVersionRef != null}"); + + // Convert references to Version objects to get all the properties + Version firstVersion = await firstAppVersionRef.GetVersion(); + Console.WriteLine($"First Version Description: {firstVersion.Description}"); + + // ChangeLog, Version and Change objects can all have additional data stored within them (set in the WPF app) + // You can access this data by deserializing the AdditionalData property (it is a JObject) + // For example, to retrieve additional data from a version + ExtraVersionData extraData = firstVersion.AdditionalData.ToObject(); + + // ^ The version files with the given URI don't actually use additional data so this is null + + // You could use this to order lists of versions or changes using Linq: + /* + List> getVersionTasks = changeLog.Versions.Select(async v => await v.GetVersion()).ToList(); + IEnumerable versions = await Task.WhenAll(getVersionTasks); + versions.OrderBy(v => v.AdditionalData.ToObject().Importance); + // It is gerenally a good idea to surround this in try{}catch{} in case ToObject throws an error + */ + + Console.ReadKey(); + + return 0; + } + + private class ExtraVersionData + { + public int Importance { get; set; } + } + } +} diff --git a/src/SimpleVersionControl.Example/Properties/AssemblyInfo.cs b/src/SimpleVersionControl.Example/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d321d7c --- /dev/null +++ b/src/SimpleVersionControl.Example/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SimpleVersionControl.Example")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SimpleVersionControl.Example")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0819fe23-85de-42a0-be15-37dedf55ad24")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/SimpleVersionControl.Example/SimpleVersionControl.Example.csproj b/src/SimpleVersionControl.Example/SimpleVersionControl.Example.csproj new file mode 100644 index 0000000..3c5fb70 --- /dev/null +++ b/src/SimpleVersionControl.Example/SimpleVersionControl.Example.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {0819FE23-85DE-42A0-BE15-37DEDF55AD24} + Exe + SimpleVersionControl.Example + SimpleVersionControl.Example + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + {0df4934a-83b0-4ee2-9486-892f6b22648c} + SimpleVersionControl + + + + \ No newline at end of file diff --git a/src/SimpleVersionControl/Exceptions/ChangeLogValidationException.cs b/src/SimpleVersionControl/Exceptions/ChangeLogValidationException.cs new file mode 100644 index 0000000..c860c0b --- /dev/null +++ b/src/SimpleVersionControl/Exceptions/ChangeLogValidationException.cs @@ -0,0 +1,17 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; + +namespace SimpleVersionControl +{ + public class ChangeLogValidationException : Exception + { + public ChangeLogValidationException(string msg) + : base(msg) + { + } + } +} diff --git a/src/SimpleVersionControl/Extensions/ChangeExtensions.cs b/src/SimpleVersionControl/Extensions/ChangeExtensions.cs new file mode 100644 index 0000000..2c59217 --- /dev/null +++ b/src/SimpleVersionControl/Extensions/ChangeExtensions.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Newtonsoft.Json; + +namespace SimpleVersionControl +{ + public static class ChangeExtensions + { + /// + /// Serializes instance of to JSON string. + /// + /// Instance of to serialize. + /// Returns JSON string. + public static string ToJson(this Change change) + { + return JsonConvert.SerializeObject(change, Formatting.Indented); + } + + /// + /// Throws if version references are not valid. + /// + /// Instance of to check version references on. + /// The instance of listing all versions. + public static void Validate(this Change change, ChangeLog changeLog) + { + if (change.ReleaseVersion == null) + { + throw new ChangeLogValidationException("Change has Release version reference missing."); + } + + bool found = false; + foreach (VersionRef versionRef in changeLog.Versions) + { + if (versionRef.VersionName == change.ReleaseVersion.VersionName && versionRef.RelativeFilePath == change.ReleaseVersion.RelativeFilePath) + { + found = true; + } + } + + if (!found) + { + throw new ChangeLogValidationException("Change has invalid version reference."); + } + } + } +} \ No newline at end of file diff --git a/src/SimpleVersionControl/Extensions/ChangeLogExtensions.cs b/src/SimpleVersionControl/Extensions/ChangeLogExtensions.cs new file mode 100644 index 0000000..82940d8 --- /dev/null +++ b/src/SimpleVersionControl/Extensions/ChangeLogExtensions.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Linq; +using Newtonsoft.Json; + +namespace SimpleVersionControl +{ + public static class ChangeLogExtensions + { + /// + /// Serializes instance of to JSON string. + /// + /// Instance of to serialize. + /// Returns JSON string. + public static string ToJson(this ChangeLog changeLog) + { + return JsonConvert.SerializeObject(changeLog, Formatting.Indented); + } + + /// + /// Throws if version names are not unique. + /// + /// Instance of to check version names from. + public static void Validate(this ChangeLog changeLog) + { + changeLog.Versions.RemoveAll(item => item == null); + bool versionNamesUnique = changeLog.Versions.Select(v => v.VersionName).Distinct().Count() == changeLog.Versions.Count; + if (!versionNamesUnique) + { + throw new ChangeLogValidationException("Duplicate Version Name Found. Version Names should be unique."); + } + } + } +} diff --git a/src/SimpleVersionControl/Extensions/References/ChangeRefExtensions.cs b/src/SimpleVersionControl/Extensions/References/ChangeRefExtensions.cs new file mode 100644 index 0000000..a81ace3 --- /dev/null +++ b/src/SimpleVersionControl/Extensions/References/ChangeRefExtensions.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Linq; +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public static class ChangeRefExtensions + { + /// + /// Asynchronously retrieves object from the filesystem given a reference to it. + /// + /// Reference to the JSON file. + /// Should the resulting Change be cached? + /// Returns Change object. + public static async Task GetChange(this ChangeRef changeRef, bool cache = true) + { + Change change = changeRef.VersionController.CachedChanges.FirstOrDefault(c => c.Guid == changeRef.Guid); + if (change != null) + { + return change; + } + + string changeJson = await changeRef.VersionController.FileProvider.GetFile(changeRef.RelativeFilePath); + if (changeJson == null) + { + return null; + } + + change = Change.FromJson(changeJson, changeRef.VersionController); + if (change != null && cache) + { + changeRef.VersionController.CachedChanges.Add(change); + } + + return change; + } + } +} diff --git a/src/SimpleVersionControl/Extensions/References/VersionRefExtensions.cs b/src/SimpleVersionControl/Extensions/References/VersionRefExtensions.cs new file mode 100644 index 0000000..098c7bd --- /dev/null +++ b/src/SimpleVersionControl/Extensions/References/VersionRefExtensions.cs @@ -0,0 +1,42 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Linq; +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public static class VersionRefExtensions + { + /// + /// Asynchronously retrieves object from the filesystem given a reference to it. + /// + /// Reference to the JSON file. + /// Should the resulting Version be cached? + /// Returns Version object. + public static async Task GetVersion(this VersionRef versionRef, bool cache = true) + { + Version version = versionRef.VersionController.CachedVersions.FirstOrDefault(v => v.VersionName == versionRef.VersionName); + if (version != null) + { + return version; + } + + string versionJson = await versionRef.VersionController.FileProvider.GetFile(versionRef.RelativeFilePath); + if (versionJson == null) + { + return null; + } + + version = Version.FromJson(versionJson, versionRef.VersionController); + if (version != null && cache) + { + versionRef.VersionController.CachedVersions.Add(version); + } + + return version; + } + } +} diff --git a/src/SimpleVersionControl/Extensions/VersionExtensions.cs b/src/SimpleVersionControl/Extensions/VersionExtensions.cs new file mode 100644 index 0000000..98e5aff --- /dev/null +++ b/src/SimpleVersionControl/Extensions/VersionExtensions.cs @@ -0,0 +1,37 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Linq; +using Newtonsoft.Json; + +namespace SimpleVersionControl +{ + public static class VersionExtensions + { + /// + /// Serializes instance of to JSON string. + /// + /// Instance of to serialize. + /// Returns JSON string. + public static string ToJson(this Version version) + { + return JsonConvert.SerializeObject(version, Formatting.Indented); + } + + /// + /// Throws if change guids are not unique. + /// + /// Instance of to check change guids from. + public static void Validate(this Version version) + { + version.Changes.RemoveAll(item => item == null); + bool changeNamesUnique = version.Changes.Select(c => c.Guid).Distinct().Count() == version.Changes.Count; + if (!changeNamesUnique) + { + throw new ChangeLogValidationException("Duplicate Change GUID Name Found. Change GUIDs should be unique."); + } + } + } +} \ No newline at end of file diff --git a/src/SimpleVersionControl/FileSystemProvider.cs b/src/SimpleVersionControl/FileSystemProvider.cs new file mode 100644 index 0000000..c2acd4e --- /dev/null +++ b/src/SimpleVersionControl/FileSystemProvider.cs @@ -0,0 +1,177 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public class FileSystemProvider : IFileProvider, IFileSaver + { + public FileSystemProvider(string rootPath) + { + RootPath = rootPath; + } + + public string RootPath { get; set; } + + public async Task GetFile(string relativePath) + { + await Task.CompletedTask; + + string completePath = Path.Combine(RootPath, relativePath); + if (!File.Exists(completePath)) + { + return null; + } + + try + { + StreamReader reader = new StreamReader(completePath); + string contents = reader.ReadToEnd(); + reader.Close(); + return contents; + } + catch + { + return null; + } + } + + public async Task SaveFile(string relativePath, string content) + { + await Task.CompletedTask; + + if (content == null) + { + return false; + } + + string completePath = Path.Combine(RootPath, relativePath); + + try + { + string dir = Path.GetDirectoryName(completePath); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + StreamWriter writer = new StreamWriter(completePath, false); + writer.Write(content); + writer.Close(); + return true; + } + catch + { + return false; + } + } + + public async Task PublishFromTemp() + { + if (!(await ClearDirectory(RootPath, false))) + { + return false; + } + + string tempPath = Path.Combine(RootPath, "temp"); + if (!Directory.Exists(tempPath)) + { + return true; + } + + DirectoryInfo dirInfo = new DirectoryInfo(tempPath); + + foreach (FileInfo fileInfo in dirInfo.EnumerateFiles()) + { + string outpath = Path.Combine(RootPath, GetRelativePath(fileInfo.FullName, tempPath)); + fileInfo.MoveTo(outpath); + } + + foreach (DirectoryInfo subdirInfo in dirInfo.EnumerateDirectories()) + { + string outpath = Path.Combine(RootPath, GetRelativePath(subdirInfo.FullName, tempPath)); + subdirInfo.MoveTo(outpath); + } + + Directory.Delete(tempPath); + return true; + } + + public async Task CancelPublish() + { + await Task.CompletedTask; + + string tempPath = Path.Combine(RootPath, "temp"); + if (!Directory.Exists(tempPath)) + { + return; + } + + Directory.Delete(tempPath); + } + + private async Task ClearDirectory(string relativePath, bool removeEmptyDirectory) + { + await Task.CompletedTask; + string dir = Path.Combine(RootPath, relativePath); + + if (!Directory.Exists(dir)) + { + return false; + } + + try + { + bool tempFound = false; + DirectoryInfo dirInfo = new DirectoryInfo(dir); + + foreach (FileInfo fileInfo in dirInfo.EnumerateFiles()) + { + fileInfo.Delete(); + } + + foreach (DirectoryInfo subdirInfo in dirInfo.EnumerateDirectories()) + { + if (subdirInfo.Name == "temp") + { + tempFound = true; + continue; + } + + subdirInfo.Delete(true); + } + + if (removeEmptyDirectory && !tempFound) + { + dirInfo.Delete(); + } + + return true; + } + catch (Exception e) + { + Console.WriteLine(e.Message); + return false; + } + } + + private string GetRelativePath(string filespec, string folder) + { + Uri pathUri = new Uri(filespec); + + // Folders must end in a slash + if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) + { + folder += Path.DirectorySeparatorChar; + } + + Uri folderUri = new Uri(folder); + return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar)); + } + } +} diff --git a/src/SimpleVersionControl/HttpFileProvider.cs b/src/SimpleVersionControl/HttpFileProvider.cs new file mode 100644 index 0000000..9fe130c --- /dev/null +++ b/src/SimpleVersionControl/HttpFileProvider.cs @@ -0,0 +1,55 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Net.Http; +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public class HttpFileProvider : IFileProvider + { + public HttpFileProvider(string baseUrl, HttpClient httpClient = null) + { + BaseUrl = baseUrl; + HttpClient = httpClient; + + if (HttpClient == null) + { + HttpClient = new HttpClient(); + } + } + + public string BaseUrl { get; set; } + + public HttpClient HttpClient { get; set; } + + public async Task GetFile(string relativePath) + { + int attempts = 0; + string uri = BaseUrl.EndsWith("/") ? $"{BaseUrl}{relativePath}" : $"{BaseUrl}/{relativePath}"; + while (attempts < 3) + { + attempts++; + + try + { + HttpResponseMessage response = await HttpClient.GetAsync(uri); + if (!response.IsSuccessStatusCode) + { + continue; + } + + return await response.Content.ReadAsStringAsync(); + } + catch + { + continue; + } + } + + return null; + } + } +} diff --git a/src/SimpleVersionControl/IFileProvider.cs b/src/SimpleVersionControl/IFileProvider.cs new file mode 100644 index 0000000..efe3bf4 --- /dev/null +++ b/src/SimpleVersionControl/IFileProvider.cs @@ -0,0 +1,14 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public interface IFileProvider + { + Task GetFile(string relativePath); + } +} diff --git a/src/SimpleVersionControl/IFileSaver.cs b/src/SimpleVersionControl/IFileSaver.cs new file mode 100644 index 0000000..0769c38 --- /dev/null +++ b/src/SimpleVersionControl/IFileSaver.cs @@ -0,0 +1,18 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public interface IFileSaver + { + Task SaveFile(string relativePath, string content); + + Task PublishFromTemp(); + + Task CancelPublish(); + } +} diff --git a/src/SimpleVersionControl/Models/Change.cs b/src/SimpleVersionControl/Models/Change.cs new file mode 100644 index 0000000..e0ed8c4 --- /dev/null +++ b/src/SimpleVersionControl/Models/Change.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace SimpleVersionControl +{ + public class Change + { + public Change() + { + } + + public Change(VersionController versionController, string guid, string relativePath, string title, string description, VersionRef releaseVersion, object additionalData = null) + { + VersionController = versionController; + Guid = guid; + Title = title; + Description = description; + ReleaseVersion = releaseVersion; + if (additionalData != null) + { + AdditionalData = JObject.FromObject(additionalData); + } + } + + [JsonIgnore] + public VersionController VersionController { get; internal set; } + + /// + /// A random Guid used to identify this change. + /// + [JsonProperty("guid")] + public string Guid { get; set; } + + /// + /// A short title representing this change. + /// + [JsonProperty("title")] + public string Title { get; set; } + + /// + /// A description of the change. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// A reference to the version this change was included in. + /// + [JsonProperty("release_version")] + public VersionRef ReleaseVersion { get; set; } + + /// + /// Store any additional data with each Change in this . + /// + [JsonProperty("additional_data")] + public JObject AdditionalData { get; set; } + + /// + /// Returns instance of from JSON string. + /// + /// JSON string to deserialize. + /// Version Controller reference used to cache the change object. + /// Returns Change. + public static Change FromJson(string json, VersionController versionController) + { + Change change = JsonConvert.DeserializeObject(json); + if (change != null) + { + change.VersionController = versionController; + change.ReleaseVersion.VersionController = versionController; + } + + return change; + } + } +} diff --git a/src/SimpleVersionControl/Models/ChangeLog.cs b/src/SimpleVersionControl/Models/ChangeLog.cs new file mode 100644 index 0000000..f0082da --- /dev/null +++ b/src/SimpleVersionControl/Models/ChangeLog.cs @@ -0,0 +1,62 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace SimpleVersionControl +{ + public class ChangeLog + { + public ChangeLog() + { + } + + public ChangeLog(VersionController versionController, List versions, object additionalData = null) + { + VersionController = versionController; + Versions = versions; + if (additionalData != null) + { + AdditionalData = JObject.FromObject(additionalData); + } + } + + [JsonIgnore] + public VersionController VersionController { get; internal set; } + + /// + /// List of versions of the application. + /// + [JsonProperty("versions")] + public List Versions { get; set; } + + /// + /// Store any additional data with each Change in this . + /// + [JsonProperty("additional_data")] + public JObject AdditionalData { get; set; } + + /// + /// Returns instance of from JSON string. + /// + /// JSON string to deserialize. + /// Version Controller reference used to cache the ChangeLog object. + /// Returns ChangeLog. + public static ChangeLog FromJson(string json, VersionController versionController) + { + ChangeLog changeLog = JsonConvert.DeserializeObject(json); + if (changeLog != null) + { + changeLog.VersionController = versionController; + changeLog.Versions.ToList().ForEach(v => v.VersionController = versionController); + } + + return changeLog; + } + } +} diff --git a/src/SimpleVersionControl/Models/References/ChangeRef.cs b/src/SimpleVersionControl/Models/References/ChangeRef.cs new file mode 100644 index 0000000..70c721e --- /dev/null +++ b/src/SimpleVersionControl/Models/References/ChangeRef.cs @@ -0,0 +1,38 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Newtonsoft.Json; + +namespace SimpleVersionControl +{ + public class ChangeRef + { + public ChangeRef() + { + } + + public ChangeRef(VersionController versionController, string guid, string relativePath) + { + VersionController = versionController; + Guid = guid; + RelativeFilePath = relativePath; + } + + [JsonIgnore] + public VersionController VersionController { get; internal set; } + + /// + /// A random Guid used to identify this change. + /// + [JsonProperty("guid")] + public string Guid { get; set; } + + /// + /// Relative file path to the JSON file for this change in the filesystem. + /// + [JsonProperty("relative_file_path")] + public string RelativeFilePath { get; set; } + } +} diff --git a/src/SimpleVersionControl/Models/References/VersionRef.cs b/src/SimpleVersionControl/Models/References/VersionRef.cs new file mode 100644 index 0000000..da4c972 --- /dev/null +++ b/src/SimpleVersionControl/Models/References/VersionRef.cs @@ -0,0 +1,38 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using Newtonsoft.Json; + +namespace SimpleVersionControl +{ + public class VersionRef + { + public VersionRef() + { + } + + public VersionRef(VersionController versionController, string relativePath, string versionName) + { + VersionController = versionController; + RelativeFilePath = relativePath; + VersionName = versionName; + } + + [JsonIgnore] + public VersionController VersionController { get; internal set; } + + /// + /// A unique name used to identify this version. + /// + [JsonProperty("version")] + public string VersionName { get; set; } + + /// + /// Relative file path to the JSON file for this version in the filesystem. + /// + [JsonProperty("relative_file_path")] + public string RelativeFilePath { get; set; } + } +} diff --git a/src/SimpleVersionControl/Models/Version.cs b/src/SimpleVersionControl/Models/Version.cs new file mode 100644 index 0000000..10c0936 --- /dev/null +++ b/src/SimpleVersionControl/Models/Version.cs @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace SimpleVersionControl +{ + public class Version + { + public Version() + { + } + + public Version(VersionController versionController, string versionName, string description, string downloadLink, DateTime? releaseDate, List changes, object additionalData = null) + { + VersionController = versionController; + VersionName = versionName; + Description = description; + DownloadLink = downloadLink; + ReleaseDate = releaseDate; + Changes = changes; + if (additionalData != null) + { + AdditionalData = JObject.FromObject(additionalData); + } + } + + [JsonIgnore] + public VersionController VersionController { get; internal set; } + + /// + /// A unique name used to identify this version. + /// + [JsonProperty("version")] + public string VersionName { get; set; } + + /// + /// Description of the version. + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Link to download this version from. + /// + [JsonProperty("download_link")] + public string DownloadLink { get; set; } + + /// + /// Timestamp for the release of this version. + /// + [JsonProperty("release_date")] + public DateTime? ReleaseDate { get; set; } + + /// + /// Is this version still functioning? + /// + [JsonProperty("is_functioning")] + public bool IsFunctioning { get; set; } = true; + + /// + /// List of changes made in this version. + /// + [JsonProperty("changes")] + public List Changes { get; set; } + + /// + /// Store any additional data with each Version in this . + /// + [JsonProperty("additional_data")] + public JObject AdditionalData { get; set; } + + /// + /// Returns instance of from JSON string. + /// + /// JSON string to deserialize. + /// Version Controller reference used to cache the version object. + /// Returns Version. + public static Version FromJson(string json, VersionController versionController) + { + Version version = JsonConvert.DeserializeObject(json); + if (version != null) + { + version.VersionController = versionController; + version.Changes.ToList().ForEach(v => v.VersionController = versionController); + } + + return version; + } + } +} diff --git a/src/SimpleVersionControl/SimpleVersionControl.csproj b/src/SimpleVersionControl/SimpleVersionControl.csproj new file mode 100644 index 0000000..c513be5 --- /dev/null +++ b/src/SimpleVersionControl/SimpleVersionControl.csproj @@ -0,0 +1,24 @@ + + + + netstandard2.0 + 8.0 + SimpleVersionControl + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/SimpleVersionControl/VersionController.cs b/src/SimpleVersionControl/VersionController.cs new file mode 100644 index 0000000..27e6304 --- /dev/null +++ b/src/SimpleVersionControl/VersionController.cs @@ -0,0 +1,428 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace SimpleVersionControl +{ + public class VersionController + { + /// + /// Initializes a new instance of the class. + /// + /// String representing the current version of the application. + /// Base Uri where version JSON files can be found. + /// HttpClient to retrieve JSON files with. + public VersionController(string currentVersion, string baseUrl, HttpClient httpClient = null) + : this(currentVersion, new HttpFileProvider(baseUrl, httpClient)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// String representing the current version of the application. + /// Service to retrieve JSON strings from paths. + public VersionController(string currentVersion, IFileProvider fileProvider) + { + CurrentVersion = currentVersion; + FileProvider = fileProvider; + } + + /// + /// String representing the current version of the application. + /// + public string CurrentVersion { get; internal set; } + + /// + /// Service to retrieve JSON strings from paths. + /// + public IFileProvider FileProvider { get; internal set; } + + internal ChangeLog CachedChangeLog { get; set; } + + internal List CachedChanges { get; set; } = new List(); + + internal List CachedVersions { get; set; } = new List(); + + /// + /// Is this the latest version of the application? + /// + /// True if this is the latest version. + public async Task IsLatestVersion() + { + if (await GetChangeLog() == null) + { + return false; + } + + string latestVersionString = CachedChangeLog.Versions.Last().VersionName; + return latestVersionString == CurrentVersion; + } + + /// + /// Is this version of the application still functioning? Or has it been broken by later updates. + /// + /// True if this version is still functioning. + public async Task IsFunctioningVersion() + { + Version curVersion = await GetVersion(); + if (curVersion == null) + { + return false; + } + + return curVersion.IsFunctioning; + } + + /// + /// Retrieves instance of representing the current version of the application. + /// + /// Returns current application version object. + public async Task GetVersion() + { + return await GetVersion(CurrentVersion); + } + + /// + /// Retrieves instance of representing a version of the application. + /// + /// String representing a version of the application. + /// Returns application version object. + public async Task GetVersion(string versionString) + { + VersionRef versionRef = await GetVersionRef(versionString); + if (versionRef == null) + { + return null; + } + + return await versionRef.GetVersion(); + } + + /// + /// Retrieves instance of which references a version of the application in the filesystem. + /// + /// String representing a version of the application. + /// Returns object referencing application version. + public async Task GetVersionRef(string versionString) + { + if (await GetChangeLog() == null) + { + return null; + } + + return CachedChangeLog.Versions.FirstOrDefault(v => v.VersionName == versionString); + } + + /// + /// Retrieves instance of representing the latest version of the application. + /// + /// Returns latest application version object. + public async Task GetLatestVersion() + { + VersionRef versionRef = await GetLatestVersionRef(); + if (versionRef == null) + { + return null; + } + + return await versionRef.GetVersion(); + } + + /// + /// Retrieves instance of which references the latest version of the application in the filesystem. + /// + /// Returns object referencing latest application version. + public async Task GetLatestVersionRef() + { + if (await GetChangeLog() == null) + { + return null; + } + + return CachedChangeLog.Versions.Last(); + } + + /// + /// Retrieves instance of representing the first version of the application. + /// + /// Returns latest application version object. + public async Task GetFirstVersion() + { + VersionRef versionRef = await GetLatestVersionRef(); + if (versionRef == null) + { + return null; + } + + return await versionRef.GetVersion(); + } + + /// + /// Retrieves instance of which references the first version of the application in the filesystem. + /// + /// Returns object referencing first application version. + public async Task GetFirstVersionRef() + { + if (await GetChangeLog() == null) + { + return null; + } + + return CachedChangeLog.Versions.First(); + } + + /// + /// Retrieves application changelog which lists all versions. + /// + /// Returns object representing application ChangeLog. + public async Task GetChangeLog() + { + if (CachedChangeLog != null) + { + return CachedChangeLog; + } + + string changelogContent = await FileProvider.GetFile("changelog.json"); + if (string.IsNullOrEmpty(changelogContent)) + { + return null; + } + + ChangeLog changeLog = ChangeLog.FromJson(changelogContent, this); + if (changeLog != null) + { + CachedChangeLog = changeLog; + } + + return changeLog; + } + + /// + /// Retrieves list of all application versions between two given versions. + /// + /// Name of first version. + /// Name of second version. + /// List of application version references. Null if version doesn't exist. + public async Task> GetVersionsBetween(string versionOne, string versionTwo) + { + VersionRef refOne = await GetVersionRef(versionOne); + VersionRef refTwo = await GetVersionRef(versionOne); + if (refOne == null || refTwo == null) + { + return null; + } + + return await GetVersionsBetween(refOne, refTwo); + } + + /// + /// Retrieves list of all application versions between two given versions. + /// + /// Reference to first version. + /// Reference to second version. + /// List of application version references. + public async Task> GetVersionsBetween(VersionRef versionOne, VersionRef versionTwo) + { + if (await GetChangeLog() == null) + { + return null; + } + + if (versionOne.VersionName == versionTwo.VersionName) + { + return new List(); + } + + int indexOfOne = CachedChangeLog.Versions.IndexOf(versionOne); + int indexOfTwo = CachedChangeLog.Versions.IndexOf(versionTwo); + int minIndex = Math.Min(indexOfOne, indexOfTwo); + int maxIndex = Math.Max(indexOfOne, indexOfTwo); + return CachedChangeLog.Versions.GetRange(minIndex + 1, maxIndex - minIndex - 1); + } + + /// + /// Retrieves list of all application changes between two given versions. + /// + /// Name of first version. + /// Name of second version. + /// List of references to application changes. Null if version doesn't exist. + public async Task> GetChangesBetween(string versionOne, string versionTwo) + { + VersionRef refOne = await GetVersionRef(versionOne); + VersionRef refTwo = await GetVersionRef(versionOne); + if (refOne == null || refTwo == null) + { + return null; + } + + return await GetChangesBetween(refOne, refTwo); + } + + /// + /// Retrieves list of all application changes between two given versions. + /// + /// Reference to first version. + /// Reference to second version. + /// List of references to application changes. + public async Task> GetChangesBetween(VersionRef versionOne, VersionRef versionTwo) + { + IEnumerable versionsBetween = await GetVersionsBetween(versionOne, versionTwo); + if (versionsBetween == null) + { + return null; + } + + List changes = new List(); + foreach (VersionRef versionRef in versionsBetween) + { + Version version = await versionRef.GetVersion(); + changes.AddRange(version.Changes); + } + + return changes; + } + + /// + /// Writes ChangeLog, Version and Change files to filesystem. + /// + /// True if was successful, false otherwise. + public async Task Serialize() + { + if (await GetChangeLog() == null) + { + return false; + } + + return await Serialize(CachedChangeLog); + } + + /// + /// Writes ChangeLog, Version and Change files to filesystem. + /// + /// ChangeLog to serialize. + /// True if was successful, false otherwise. + public async Task Serialize(ChangeLog changeLog) + { + if (FileProvider is IFileSaver) + { + return await Serialize(changeLog, (IFileSaver)FileProvider); + } + else + { + return false; + } + } + + /// + /// Writes ChangeLog, Version and Change files using given instance of + /// + /// ChangeLog to serialize. + /// Service to save json strings to file paths. + /// True if was successful, false otherwise. + public async Task Serialize(ChangeLog changeLog, IFileSaver saver) + { + if (changeLog == null) + { + return false; + } + + try + { + changeLog.Validate(); + } + catch (ChangeLogValidationException) + { + await saver.CancelPublish(); + throw; + } + + if (!(await saver.SaveFile(Path.Combine("temp", "changelog.json"), changeLog.ToJson()))) + { + return false; + } + + foreach (VersionRef versionRef in changeLog.Versions) + { + Version version = await versionRef.GetVersion(false); + version.Changes.RemoveAll(c => c == null); + if (version == null) + { + continue; + } + + try + { + version.Validate(); + } + catch (ChangeLogValidationException) + { + await saver.CancelPublish(); + throw; + } + + if (!(await saver.SaveFile(Path.Combine("temp", version.VersionName, "version.json"), version.ToJson()))) + { + return false; + } + + foreach (ChangeRef changeRef in version.Changes) + { + Change change = await changeRef.GetChange(false); + if (change == null) + { + continue; + } + + try + { + change.Validate(changeLog); + } + catch (ChangeLogValidationException) + { + await saver.CancelPublish(); + throw; + } + + if (!(await saver.SaveFile(Path.Combine("temp", version.VersionName, "changes", $"{change.Guid}.json"), change.ToJson()))) + { + return false; + } + } + } + + bool success = await saver.PublishFromTemp(); + + // Clear caches + CachedChangeLog = null; + CachedVersions = new List(); + CachedChanges = new List(); + + return success; + } + + public void CacheVersion(Version version) + { + if (CachedVersions.FirstOrDefault(v => v.VersionName == version.VersionName) == null) + { + CachedVersions.Add(version); + } + } + + public void CacheChange(Change change) + { + if (CachedChanges.FirstOrDefault(c => c.Guid == change.Guid) == null) + { + CachedChanges.Add(change); + } + } + } +} diff --git a/src/TextEditLib/AssemblyInfo.cs b/src/TextEditLib/AssemblyInfo.cs new file mode 100644 index 0000000..b8ea9cc --- /dev/null +++ b/src/TextEditLib/AssemblyInfo.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +using System.Windows; + +[assembly: ThemeInfo( + + // where theme specific resource dictionaries are located + // (used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.None, + + // where the generic resource dictionary is located + // (used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) + ResourceDictionaryLocation.SourceAssembly +)] diff --git a/src/TextEditLib/Extensions/HighlightCurrentLineBackgroundRenderer.cs b/src/TextEditLib/Extensions/HighlightCurrentLineBackgroundRenderer.cs new file mode 100644 index 0000000..48a9d41 --- /dev/null +++ b/src/TextEditLib/Extensions/HighlightCurrentLineBackgroundRenderer.cs @@ -0,0 +1,94 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace TextEditLib.Extensions +{ + using ICSharpCode.AvalonEdit; + using ICSharpCode.AvalonEdit.Rendering; + using System.Windows.Media; + using System.Windows; + + /// + /// AvalonEdit: highlight current line even when not focused + /// + /// Source: http://stackoverflow.com/questions/5072761/avalonedit-highlight-current-line-even-when-not-focused + /// + internal class HighlightCurrentLineBackgroundRenderer : IBackgroundRenderer + { + #region fields + private readonly TextEdit _Editor; + #endregion fields + + #region ctors + /// + /// Class Constructor from editor and SolidColorBrush definition + /// + /// + public HighlightCurrentLineBackgroundRenderer(TextEdit editor) + : this() + { + _Editor = editor; + } + + /// + /// Hidden class standard constructor + /// + protected HighlightCurrentLineBackgroundRenderer() + { + // Nothing to initialize here... + } + #endregion ctors + + #region properties + /// + /// Get the of the control. + /// + public KnownLayer Layer + { + get { return KnownLayer.Background; } + } + #endregion properties + + #region methods + /// + /// Draw the background line highlighting of the current line. + /// + /// + /// + public void Draw(TextView textView, DrawingContext drawingContext) + { + if (this._Editor == null) + return; + + if (this._Editor.Document == null) + return; + + if (_Editor.EditorCurrentLineBorderThickness == 0 && _Editor.EditorCurrentLineBackground == null) + return; + + Pen borderPen = null; + + if (_Editor.EditorCurrentLineBorder != null) + { + borderPen = new Pen(_Editor.EditorCurrentLineBorder, _Editor.EditorCurrentLineBorderThickness); + + if (borderPen.CanFreeze) + borderPen.Freeze(); + } + + textView.EnsureVisualLines(); + var currentLine = _Editor.Document.GetLineByOffset(_Editor.CaretOffset); + + foreach (var rect in BackgroundGeometryBuilder.GetRectsForSegment(textView, currentLine)) + { + drawingContext.DrawRectangle(_Editor.EditorCurrentLineBackground, borderPen, + new Rect(rect.Location, new Size(textView.ActualWidth, rect.Height))); + } + } + #endregion methods + } +} diff --git a/src/TextEditLib/Resources/Icons/Copy.ico b/src/TextEditLib/Resources/Icons/Copy.ico new file mode 100644 index 0000000..9dbed6c Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Copy.ico differ diff --git a/src/TextEditLib/Resources/Icons/Copy_16x.svg b/src/TextEditLib/Resources/Icons/Copy_16x.svg new file mode 100644 index 0000000..3de60b0 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Copy_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/Resources/Icons/Cut.ico b/src/TextEditLib/Resources/Icons/Cut.ico new file mode 100644 index 0000000..9158d44 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Cut.ico differ diff --git a/src/TextEditLib/Resources/Icons/Cut_16x.svg b/src/TextEditLib/Resources/Icons/Cut_16x.svg new file mode 100644 index 0000000..a28dbe1 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Cut_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/Resources/Icons/Delete.ico b/src/TextEditLib/Resources/Icons/Delete.ico new file mode 100644 index 0000000..1f87ec0 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Delete.ico differ diff --git a/src/TextEditLib/Resources/Icons/Delete_16x.svg b/src/TextEditLib/Resources/Icons/Delete_16x.svg new file mode 100644 index 0000000..f57d134 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Delete_16x.svg @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/TextEditLib/Resources/Icons/OpenFile.ico b/src/TextEditLib/Resources/Icons/OpenFile.ico new file mode 100644 index 0000000..7b5dac9 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/OpenFile.ico differ diff --git a/src/TextEditLib/Resources/Icons/OpenFile_16x.svg b/src/TextEditLib/Resources/Icons/OpenFile_16x.svg new file mode 100644 index 0000000..9d8f471 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/OpenFile_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/Resources/Icons/Paste.ico b/src/TextEditLib/Resources/Icons/Paste.ico new file mode 100644 index 0000000..d5ec440 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Paste.ico differ diff --git a/src/TextEditLib/Resources/Icons/Paste_16x.svg b/src/TextEditLib/Resources/Icons/Paste_16x.svg new file mode 100644 index 0000000..144e0ee --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Paste_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/Resources/Icons/Redo.ico b/src/TextEditLib/Resources/Icons/Redo.ico new file mode 100644 index 0000000..ba10802 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Redo.ico differ diff --git a/src/TextEditLib/Resources/Icons/Redo_16x.svg b/src/TextEditLib/Resources/Icons/Redo_16x.svg new file mode 100644 index 0000000..f199952 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Redo_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/Resources/Icons/Undo.ico b/src/TextEditLib/Resources/Icons/Undo.ico new file mode 100644 index 0000000..5d68af8 Binary files /dev/null and b/src/TextEditLib/Resources/Icons/Undo.ico differ diff --git a/src/TextEditLib/Resources/Icons/Undo_16x.svg b/src/TextEditLib/Resources/Icons/Undo_16x.svg new file mode 100644 index 0000000..b0fa322 --- /dev/null +++ b/src/TextEditLib/Resources/Icons/Undo_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/TextEditLib/TextEdit.xaml b/src/TextEditLib/TextEdit.xaml new file mode 100644 index 0000000..d220d52 --- /dev/null +++ b/src/TextEditLib/TextEdit.xaml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/TextEditLib/TextEdit.xaml.cs b/src/TextEditLib/TextEdit.xaml.cs new file mode 100644 index 0000000..e400a0b --- /dev/null +++ b/src/TextEditLib/TextEdit.xaml.cs @@ -0,0 +1,123 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace TextEditLib +{ + using ICSharpCode.AvalonEdit; + using System.Windows; + using System.Windows.Media; + using TextEditLib.Extensions; + + /// + /// Implements an AvalonEdit control textedit control with extensions. + /// + public class TextEdit : TextEditor + { + #region fields + #region EditorCurrentLine Highlighting Colors + public static readonly DependencyProperty EditorCurrentLineBackgroundProperty = + DependencyProperty.Register("EditorCurrentLineBackground", + typeof(Brush), + typeof(TextEdit), + new UIPropertyMetadata(new SolidColorBrush(Colors.Transparent))); + + public static readonly DependencyProperty EditorCurrentLineBorderProperty = + DependencyProperty.Register("EditorCurrentLineBorder", typeof(Brush), + typeof(TextEdit), new PropertyMetadata(new SolidColorBrush( + Color.FromArgb(0x60, SystemColors.HighlightBrush.Color.R, + SystemColors.HighlightBrush.Color.G, + SystemColors.HighlightBrush.Color.B)))); + + public static readonly DependencyProperty EditorCurrentLineBorderThicknessProperty = + DependencyProperty.Register("EditorCurrentLineBorderThickness", typeof(double), + typeof(TextEdit), new PropertyMetadata(2.0d)); + #endregion EditorCurrentLine Highlighting Colors + #endregion fields + + #region ctors + /// + /// Static class constructor + /// + static TextEdit() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TextEdit), + new FrameworkPropertyMetadata(typeof(TextEdit))); + } + + /// + /// Class constructor + /// + public TextEdit() + { + this.Loaded += TextEdit_Loaded; + } + #endregion ctors + + #region properties + #region EditorCurrentLine Highlighting Colors + /// + /// Style the background color of the current editor line + /// + public Brush EditorCurrentLineBackground + { + get { return (Brush)GetValue(EditorCurrentLineBackgroundProperty); } + set { SetValue(EditorCurrentLineBackgroundProperty, value); } + } + + public Brush EditorCurrentLineBorder + { + get { return (Brush)GetValue(EditorCurrentLineBorderProperty); } + set { SetValue(EditorCurrentLineBorderProperty, value); } + } + + public double EditorCurrentLineBorderThickness + { + get { return (double)GetValue(EditorCurrentLineBorderThicknessProperty); } + set { SetValue(EditorCurrentLineBorderThicknessProperty, value); } + } + #endregion EditorCurrentLine Highlighting Colors + #endregion properties + + #region methods + /// + /// Method is invoked when the control is loaded for the first time. + /// + /// + /// + private void TextEdit_Loaded(object sender, RoutedEventArgs e) + { + AdjustCurrentLineBackground(); + } + + /// + /// Reset the to be used for highlighting the current editor line. + /// + private void AdjustCurrentLineBackground() + { + HighlightCurrentLineBackgroundRenderer oldRenderer = null; + + // Make sure there is only one of this type of background renderer + // Otherwise, we might keep adding and WPF keeps drawing them on top of each other + foreach (var item in this.TextArea.TextView.BackgroundRenderers) + { + if (item != null) + { + if (item is HighlightCurrentLineBackgroundRenderer) + { + oldRenderer = item as HighlightCurrentLineBackgroundRenderer; + } + } + } + + if (oldRenderer != null) + this.TextArea.TextView.BackgroundRenderers.Remove(oldRenderer); + + this.TextArea.TextView.BackgroundRenderers.Add(new HighlightCurrentLineBackgroundRenderer(this)); + } + #endregion methods + } +} diff --git a/src/TextEditLib/TextEditLib.csproj b/src/TextEditLib/TextEditLib.csproj new file mode 100644 index 0000000..988bd2b --- /dev/null +++ b/src/TextEditLib/TextEditLib.csproj @@ -0,0 +1,77 @@ + + + + netcoreapp3.0;net4.5.2 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + TextEdit.xaml + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + Designer + + + Designer + + + Designer + + + Designer + + + diff --git a/src/TextEditLib/Themes/DarkBrushs.xaml b/src/TextEditLib/Themes/DarkBrushs.xaml new file mode 100644 index 0000000..401809b --- /dev/null +++ b/src/TextEditLib/Themes/DarkBrushs.xaml @@ -0,0 +1,89 @@ + + + #1ba1e2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/TextEditLib/Themes/Generic.xaml b/src/TextEditLib/Themes/Generic.xaml new file mode 100644 index 0000000..394037f --- /dev/null +++ b/src/TextEditLib/Themes/Generic.xaml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/TextEditLib/Themes/Icons.xaml b/src/TextEditLib/Themes/Icons.xaml new file mode 100644 index 0000000..3fe1b7f --- /dev/null +++ b/src/TextEditLib/Themes/Icons.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/TextEditLib/Themes/LightBrushs.xaml b/src/TextEditLib/Themes/LightBrushs.xaml new file mode 100644 index 0000000..9093a5c --- /dev/null +++ b/src/TextEditLib/Themes/LightBrushs.xaml @@ -0,0 +1,89 @@ + + + + #1ba1e2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/TextEditLib/Themes/ResourceKeys.cs b/src/TextEditLib/Themes/ResourceKeys.cs new file mode 100644 index 0000000..1b96fbe --- /dev/null +++ b/src/TextEditLib/Themes/ResourceKeys.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------------------------- +// Simple Version Control - © Copyright 2020 - Jam-Es.com +// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +// ------------------------------------------------------------------------------------------------- + +#pragma warning disable + +namespace TextEditLib.Themes +{ + using System.Windows; + + public static class ResourceKeys + { + #region Accent Keys + /// + /// Accent Color Key - This Color key is used to accent elements in the UI + /// (e.g.: Color of Activated Normal Window Frame, ResizeGrip, Focus or MouseOver input elements) + /// + public static readonly ComponentResourceKey ControlAccentColorKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlAccentColorKey"); + + /// + /// Accent Brush Key - This Brush key is used to accent elements in the UI + /// (e.g.: Color of Activated Normal Window Frame, ResizeGrip, Focus or MouseOver input elements) + /// + public static readonly ComponentResourceKey ControlAccentBrushKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlAccentBrushKey"); + #endregion Accent Keys + + #region TextEditor BrushKeys + public static readonly ComponentResourceKey EditorBackground = new ComponentResourceKey(typeof(ResourceKeys), "EditorBackground"); + public static readonly ComponentResourceKey EditorForeground = new ComponentResourceKey(typeof(ResourceKeys), "EditorForeground"); + public static readonly ComponentResourceKey EditorLineNumbersForeground = new ComponentResourceKey(typeof(ResourceKeys), "EditorLineNumbersForeground"); + public static readonly ComponentResourceKey EditorSelectionBrush = new ComponentResourceKey(typeof(ResourceKeys), "EditorSelectionBrush"); + public static readonly ComponentResourceKey EditorSelectionBorder = new ComponentResourceKey(typeof(ResourceKeys), "EditorSelectionBorder"); + public static readonly ComponentResourceKey EditorNonPrintableCharacterBrush = new ComponentResourceKey(typeof(ResourceKeys), "EditorNonPrintableCharacterBrush"); + public static readonly ComponentResourceKey EditorLinkTextForegroundBrush = new ComponentResourceKey(typeof(ResourceKeys), "EditorLinkTextForegroundBrush"); + public static readonly ComponentResourceKey EditorLinkTextBackgroundBrush = new ComponentResourceKey(typeof(ResourceKeys), "EditorLinkTextBackgroundBrush"); + + #region DiffView Currentline Keys + /// + /// Gets the background color for highlighting for the currently highlighed line. + /// + public static readonly ComponentResourceKey EditorCurrentLineBackgroundBrushKey = new ComponentResourceKey(typeof(ResourceKeys), "EditorCurrentLineBackgroundBrushKey"); + + /// + /// Gets the border color for highlighting for the currently highlighed line. + /// + public static readonly ComponentResourceKey EditorCurrentLineBorderBrushKey = new ComponentResourceKey(typeof(ResourceKeys), "EditorCurrentLineBorderBrushKey"); + + /// + /// Gets the border thickness for highlighting for the currently highlighed line. + /// + public static readonly ComponentResourceKey EditorCurrentLineBorderThicknessKey = new ComponentResourceKey(typeof(ResourceKeys), "EditorCurrentLineBorderThicknessKey"); + #endregion DiffView Currentline Keys + #endregion TextEditor BrushKeys + } +} diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 0000000..b08df69 --- /dev/null +++ b/stylecop.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "Jam-Es.com", + "copyrightText": "-------------------------------------------------------------------------------------------------\nSimple Version Control - © Copyright 2020 - {companyName}\nLicensed under the {licenseName} License ({licenseName}). See {licenseFile} in the repo root for license information.\n-------------------------------------------------------------------------------------------------", + "variables": { + "licenseName": "MIT", + "licenseFile": "LICENSE" + }, + "xmlHeader": false, + "headerDecoration": "-------------------------------------------------------------------------------------------------" + }, + "orderingRules": { + "systemUsingDirectivesFirst": true, + "usingDirectivesPlacement": "outsideNamespace", + "elementOrder": [ + "kind" + ] + }, + "indentation": { + "useTabs": false, + "indentationSize": 4, + "tabSize": 4 + } + } +}