summaryrefslogtreecommitdiffstats
path: root/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs')
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs192
1 files changed, 102 insertions, 90 deletions
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
index c7eac42211..d16d6d5041 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
+++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
@@ -12,12 +12,11 @@
//
//===----------------------------------------------------------------------===//
-using Microsoft.VisualStudio.Editor;
+using EnvDTE;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
-using Microsoft.VisualStudio.TextManager.Interop;
using System;
using System.Collections;
using System.ComponentModel;
@@ -25,6 +24,7 @@ using System.ComponentModel.Design;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml.Linq;
+using System.Linq;
namespace LLVM.ClangFormat
{
@@ -36,6 +36,17 @@ namespace LLVM.ClangFormat
private string fallbackStyle = "LLVM";
private bool sortIncludes = false;
private string style = "file";
+ private bool formatOnSave = false;
+ private string formatOnSaveFileExtensions =
+ ".c;.cpp;.cxx;.cc;.tli;.tlh;.h;.hh;.hpp;.hxx;.hh;.inl" +
+ ".java;.js;.ts;.m;.mm;.proto;.protodevel;.td";
+
+ public OptionPageGrid Clone()
+ {
+ // Use MemberwiseClone to copy value types.
+ var clone = (OptionPageGrid)MemberwiseClone();
+ return clone;
+ }
public class StyleConverter : TypeConverter
{
@@ -74,7 +85,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Style")]
[Description("Coding style, currently supports:\n" +
" - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit').\n" +
@@ -121,7 +132,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Assume Filename")]
[Description("When reading from stdin, clang-format assumes this " +
"filename to look for a style config file (with 'file' style) " +
@@ -142,7 +153,7 @@ namespace LLVM.ClangFormat
}
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Fallback Style")]
[Description("The name of the predefined style used as a fallback in case clang-format " +
"is invoked with 'file' style, but can not find the configuration file.\n" +
@@ -154,7 +165,7 @@ namespace LLVM.ClangFormat
set { fallbackStyle = value; }
}
- [Category("LLVM/Clang")]
+ [Category("Format Options")]
[DisplayName("Sort includes")]
[Description("Sort touched include lines.\n\n" +
"See also: http://clang.llvm.org/docs/ClangFormat.html.")]
@@ -163,20 +174,48 @@ namespace LLVM.ClangFormat
get { return sortIncludes; }
set { sortIncludes = value; }
}
+
+ [Category("Format On Save")]
+ [DisplayName("Enable")]
+ [Description("Enable running clang-format when modified files are saved. " +
+ "Will only format if Style is found (ignores Fallback Style)."
+ )]
+ public bool FormatOnSave
+ {
+ get { return formatOnSave; }
+ set { formatOnSave = value; }
+ }
+
+ [Category("Format On Save")]
+ [DisplayName("File extensions")]
+ [Description("When formatting on save, clang-format will be applied only to " +
+ "files with these extensions.")]
+ public string FormatOnSaveFileExtensions
+ {
+ get { return formatOnSaveFileExtensions; }
+ set { formatOnSaveFileExtensions = value; }
+ }
}
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
+ [ProvideAutoLoad(UIContextGuids80.SolutionExists)] // Load package on solution load
[Guid(GuidList.guidClangFormatPkgString)]
[ProvideOptionPage(typeof(OptionPageGrid), "LLVM/Clang", "ClangFormat", 0, 0, true)]
public sealed class ClangFormatPackage : Package
{
#region Package Members
+
+ RunningDocTableEventsDispatcher _runningDocTableEventsDispatcher;
+
protected override void Initialize()
{
base.Initialize();
+ _runningDocTableEventsDispatcher = new RunningDocTableEventsDispatcher(this);
+ _runningDocTableEventsDispatcher.BeforeSave += OnBeforeSave;
+
var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
{
@@ -195,6 +234,11 @@ namespace LLVM.ClangFormat
}
#endregion
+ OptionPageGrid GetUserOptions()
+ {
+ return (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
+ }
+
private void MenuItemCallback(object sender, EventArgs args)
{
var mc = sender as System.ComponentModel.Design.MenuCommand;
@@ -204,21 +248,45 @@ namespace LLVM.ClangFormat
switch (mc.CommandID.ID)
{
case (int)PkgCmdIDList.cmdidClangFormatSelection:
- FormatSelection();
+ FormatSelection(GetUserOptions());
break;
case (int)PkgCmdIDList.cmdidClangFormatDocument:
- FormatDocument();
+ FormatDocument(GetUserOptions());
break;
}
}
+ private static bool FileHasExtension(string filePath, string fileExtensions)
+ {
+ var extensions = fileExtensions.ToLower().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+ return extensions.Contains(Path.GetExtension(filePath).ToLower());
+ }
+
+ private void OnBeforeSave(object sender, Document document)
+ {
+ var options = GetUserOptions();
+
+ if (!options.FormatOnSave)
+ return;
+
+ if (!FileHasExtension(document.FullName, options.FormatOnSaveFileExtensions))
+ return;
+
+ if (!Vsix.IsDocumentDirty(document))
+ return;
+
+ var optionsWithNoFallbackStyle = GetUserOptions().Clone();
+ optionsWithNoFallbackStyle.FallbackStyle = "none";
+ FormatDocument(document, optionsWithNoFallbackStyle);
+ }
+
/// <summary>
/// Runs clang-format on the current selection
/// </summary>
- private void FormatSelection()
+ private void FormatSelection(OptionPageGrid options)
{
- IWpfTextView view = GetCurrentView();
+ IWpfTextView view = Vsix.GetCurrentView();
if (view == null)
// We're not in a text view.
return;
@@ -231,34 +299,43 @@ namespace LLVM.ClangFormat
// of the file.
if (start >= text.Length && text.Length > 0)
start = text.Length - 1;
- string path = GetDocumentParent(view);
- string filePath = GetDocumentPath(view);
+ string path = Vsix.GetDocumentParent(view);
+ string filePath = Vsix.GetDocumentPath(view);
- RunClangFormatAndApplyReplacements(text, start, length, path, filePath, view);
+ RunClangFormatAndApplyReplacements(text, start, length, path, filePath, options, view);
}
/// <summary>
/// Runs clang-format on the current document
/// </summary>
- private void FormatDocument()
+ private void FormatDocument(OptionPageGrid options)
+ {
+ FormatView(Vsix.GetCurrentView(), options);
+ }
+
+ private void FormatDocument(Document document, OptionPageGrid options)
+ {
+ FormatView(Vsix.GetDocumentView(document), options);
+ }
+
+ private void FormatView(IWpfTextView view, OptionPageGrid options)
{
- IWpfTextView view = GetCurrentView();
if (view == null)
// We're not in a text view.
return;
- string filePath = GetDocumentPath(view);
+ string filePath = Vsix.GetDocumentPath(view);
var path = Path.GetDirectoryName(filePath);
string text = view.TextBuffer.CurrentSnapshot.GetText();
- RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, view);
+ RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, options, view);
}
- private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, IWpfTextView view)
+ private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, OptionPageGrid options, IWpfTextView view)
{
try
{
- string replacements = RunClangFormat(text, offset, length, path, filePath);
+ string replacements = RunClangFormat(text, offset, length, path, filePath, options);
ApplyClangFormatReplacements(replacements, view);
}
catch (Exception e)
@@ -283,7 +360,7 @@ namespace LLVM.ClangFormat
///
/// Formats the text range starting at offset of the given length.
/// </summary>
- private string RunClangFormat(string text, int offset, int length, string path, string filePath)
+ private static string RunClangFormat(string text, int offset, int length, string path, string filePath, OptionPageGrid options)
{
string vsixPath = Path.GetDirectoryName(
typeof(ClangFormatPackage).Assembly.Location);
@@ -293,16 +370,16 @@ namespace LLVM.ClangFormat
process.StartInfo.FileName = vsixPath + "\\clang-format.exe";
// Poor man's escaping - this will not work when quotes are already escaped
// in the input (but we don't need more).
- string style = GetStyle().Replace("\"", "\\\"");
- string fallbackStyle = GetFallbackStyle().Replace("\"", "\\\"");
+ string style = options.Style.Replace("\"", "\\\"");
+ string fallbackStyle = options.FallbackStyle.Replace("\"", "\\\"");
process.StartInfo.Arguments = " -offset " + offset +
" -length " + length +
" -output-replacements-xml " +
" -style \"" + style + "\"" +
" -fallback-style \"" + fallbackStyle + "\"";
- if (GetSortIncludes())
+ if (options.SortIncludes)
process.StartInfo.Arguments += " -sort-includes ";
- string assumeFilename = GetAssumeFilename();
+ string assumeFilename = options.AssumeFilename;
if (string.IsNullOrEmpty(assumeFilename))
assumeFilename = filePath;
if (!string.IsNullOrEmpty(assumeFilename))
@@ -352,7 +429,7 @@ namespace LLVM.ClangFormat
/// <summary>
/// Applies the clang-format replacements (xml) to the current view
/// </summary>
- private void ApplyClangFormatReplacements(string replacements, IWpfTextView view)
+ private static void ApplyClangFormatReplacements(string replacements, IWpfTextView view)
{
// clang-format returns no replacements if input text is empty
if (replacements.Length == 0)
@@ -369,70 +446,5 @@ namespace LLVM.ClangFormat
}
edit.Apply();
}
-
- /// <summary>
- /// Returns the currently active view if it is a IWpfTextView.
- /// </summary>
- private IWpfTextView GetCurrentView()
- {
- // The SVsTextManager is a service through which we can get the active view.
- var textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
- IVsTextView textView;
- textManager.GetActiveView(1, null, out textView);
-
- // Now we have the active view as IVsTextView, but the text interfaces we need
- // are in the IWpfTextView.
- var userData = (IVsUserData)textView;
- if (userData == null)
- return null;
- Guid guidWpfViewHost = DefGuidList.guidIWpfTextViewHost;
- object host;
- userData.GetData(ref guidWpfViewHost, out host);
- return ((IWpfTextViewHost)host).TextView;
- }
-
- private string GetStyle()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.Style;
- }
-
- private string GetAssumeFilename()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.AssumeFilename;
- }
-
- private string GetFallbackStyle()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.FallbackStyle;
- }
-
- private bool GetSortIncludes()
- {
- var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
- return page.SortIncludes;
- }
-
- private string GetDocumentParent(IWpfTextView view)
- {
- ITextDocument document;
- if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
- {
- return Directory.GetParent(document.FilePath).ToString();
- }
- return null;
- }
-
- private string GetDocumentPath(IWpfTextView view)
- {
- ITextDocument document;
- if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
- {
- return document.FilePath;
- }
- return null;
- }
}
}