using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.Linq; using GitUIPluginInterfaces; namespace GitCommands { public interface ICommitTemplateManager { /// <summary> /// Gets the collection of all currently registered commit templates provided by plugins. /// </summary> IEnumerable<CommitTemplateItem> RegisteredTemplates { get; } /// <summary> /// Loads commit template from the file specified in .git/config /// under <c>commit.template</c> setting. /// </summary> /// <exception cref="FileNotFoundException">The specified template file cannot be found.</exception> /// <returns>The commit template, if it is specified; otherwise <see langword="null"/>.</returns> /// <remarks> /// Template file can be set by the following command: /// <c>$ git config --global commit.template ~/.git_commit_msg.txt</c> /// </remarks> string LoadGitCommitTemplate(); /// <summary> /// Allows a plugin to register a new commit template. /// </summary> /// <param name="templateName">The name of the template.</param> /// <param name="templateText">The body of the template.</param> void Register(string templateName, Func<string> templateText); /// <summary> /// Allows a plugin to unregister a commit template. /// </summary> /// <param name="templateName">The name of the template.</param> void Unregister(string templateName); } public sealed class CommitTemplateManager : ICommitTemplateManager { private static readonly ConcurrentDictionary<string, Func<string>> RegisteredTemplatesDic = new ConcurrentDictionary<string, Func<string>>(); private readonly IFileSystem _fileSystem; private readonly IGitModule _module; private readonly IFullPathResolver _fullPathResolver; public CommitTemplateManager(IGitModule module, IFullPathResolver fullPathResolver, IFileSystem fileSystem) { _module = module; _fullPathResolver = fullPathResolver; _fileSystem = fileSystem; } public CommitTemplateManager(IGitModule module) : this(module, new FullPathResolver(() => module.WorkingDir), new FileSystem()) { } /// <summary> /// Gets the collection of all currently registered commit templates provided by plugins. /// </summary> public IEnumerable<CommitTemplateItem> RegisteredTemplates => RegisteredTemplatesDic.Select(item => new CommitTemplateItem(item.Key, item.Value())); /// <summary> /// Loads commit template from the file specified in .git/config /// under <c>commit.template</c> setting. /// </summary> /// <exception cref="FileNotFoundException">The specified template file cannot be found.</exception> /// <returns>The commit template, if it is specified; otherwise <see langword="null"/>.</returns> /// <remarks> /// Template file can be set by the following command: /// <c>$ git config --global commit.template ~/.git_commit_msg.txt</c> /// </remarks> public string LoadGitCommitTemplate() { string fileName = _module.GetEffectiveSetting("commit.template"); if (string.IsNullOrEmpty(fileName)) { return null; } fileName = _fullPathResolver.Resolve(fileName); if (!_fileSystem.File.Exists(fileName)) { throw new FileNotFoundException("File not found", fileName); } string commitTemplate = _fileSystem.File.ReadAllText(fileName); return commitTemplate; } /// <summary> /// Allows a plugin to register a new commit template. /// </summary> /// <param name="templateName">The name of the template.</param> /// <param name="templateText">The body of the template.</param> public void Register(string templateName, Func<string> templateText) { RegisteredTemplatesDic.TryAdd(templateName, templateText); } /// <summary> /// Allows a plugin to unregister a commit template. /// </summary> /// <param name="templateName">The name of the template.</param> public void Unregister(string templateName) { RegisteredTemplatesDic.TryRemove(templateName, out _); } } }