ClangFormatPackage.cs revision 22d58ddc9e3cb01ef2d736a27759cda39a336b95
115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//===-- ClangFormatPackages.cs - VSPackage for clang-format ------*- C# -*-===//
215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//
315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//                     The LLVM Compiler Infrastructure
415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//
515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek// This file is distributed under the University of Illinois Open Source
615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek// License. See LICENSE.TXT for details.
715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//
815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//===----------------------------------------------------------------------===//
915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//
1015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek// This class contains a VS extension package that runs clang-format over a
1115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek// selection in a VS text editor.
1215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//
1315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek//===----------------------------------------------------------------------===//
1415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
1515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.Editor;
1615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.Shell;
1715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.Shell.Interop;
1815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.Text;
1915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.Text.Editor;
2015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing Microsoft.VisualStudio.TextManager.Interop;
2115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System;
2215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System.ComponentModel;
2315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System.ComponentModel.Design;
2415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System.IO;
2515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System.Runtime.InteropServices;
2615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimekusing System.Xml.Linq;
2715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
2815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimeknamespace LLVM.ClangFormat
2915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek{
3015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [ClassInterface(ClassInterfaceType.AutoDual)]
3115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [CLSCompliant(false), ComVisible(true)]
3215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    public class OptionPageGrid : DialogPage
3315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    {
3415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private string style = "File";
3515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
3615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        [Category("LLVM/Clang")]
3715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        [DisplayName("Style")]
3815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        [Description("Coding style, currently supports:\n" +
3915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla').\n" +
4015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  - 'File' to search for a YAML .clang-format configuration.\n" +
4115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  - A YAML configuration snippet.\n\n" +
4215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "'File':\n" +
4315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  Searches for a .clang-format configuration in the source file's\n" +
4415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  directory and its parents.\n\n" +
4515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "YAML configuration snippet:\n" +
4615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  The content of a .clang-format configuration file, as string.\n" +
4715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "  Example: '{BasedOnStyle: \"LLVM\", IndentWidth: 8}'\n\n" +
4815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                     "See also: http://clang.llvm.org/docs/ClangFormatStyleOptions.html.")]
4915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        public string Style
5015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
5115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            get { return style; }
5215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            set { style = value; }
5315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
5415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    }
5515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
5615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [PackageRegistration(UseManagedResourcesOnly = true)]
5715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
5815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [ProvideMenuResource("Menus.ctmenu", 1)]
5915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [Guid(GuidList.guidClangFormatPkgString)]
6015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    [ProvideOptionPage(typeof(OptionPageGrid), "LLVM/Clang", "ClangFormat", 0, 0, true)]
6115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    public sealed class ClangFormatPackage : Package
6215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    {
6315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        #region Package Members
6415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        protected override void Initialize()
6515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
6615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            base.Initialize();
6715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
6815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
6915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (commandService != null)
7015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            {
7115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var menuCommandID = new CommandID(GuidList.guidClangFormatCmdSet, (int)PkgCmdIDList.cmdidClangFormat);
7215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
7315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                commandService.AddCommand(menuItem);
7415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            }
7515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
7615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        #endregion
7715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
7815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private void MenuItemCallback(object sender, EventArgs args)
7915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
8015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            IWpfTextView view = GetCurrentView();
8115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (view == null)
8215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                // We're not in a text view.
8315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                return;
8415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            string text = view.TextBuffer.CurrentSnapshot.GetText();
8515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            int start = view.Selection.Start.Position.GetContainingLine().Start.Position;
8615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            int end = view.Selection.End.Position.GetContainingLine().End.Position;
8715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            int length = end - start;
8815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // clang-format doesn't support formatting a range that starts at the end
8915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // of the file.
9015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (start >= text.Length && text.Length > 0)
9115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                start = text.Length - 1;
9215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            string path = GetDocumentParent(view);
9315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            try
9415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            {
9515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var root = XElement.Parse(RunClangFormat(text, start, length, path));
9615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var edit = view.TextBuffer.CreateEdit();
9715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                foreach (XElement replacement in root.Descendants("replacement"))
9815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                {
9915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                    var span = new Span(
10015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        int.Parse(replacement.Attribute("offset").Value),
10115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        int.Parse(replacement.Attribute("length").Value));
10215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                    edit.Replace(span, replacement.Value);
10315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                }
10415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                edit.Apply();
10515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            }
10615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            catch (Exception e)
10715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            {
10815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
10915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                var id = Guid.Empty;
11015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                int result;
11115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                uiShell.ShowMessageBox(
11215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        0, ref id,
11315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        "Error while running clang-format:",
11415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        e.Message,
11515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        string.Empty, 0,
11615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
11715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
11815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        OLEMSGICON.OLEMSGICON_INFO,
11915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                        0, out result);
12015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            }
12115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
12215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
12315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// <summary>
12415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// Runs the given text through clang-format and returns the replacements as XML.
12515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        ///
12615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// Formats the text range starting at offset of the given length.
12715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// </summary>
12815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private string RunClangFormat(string text, int offset, int length, string path)
12915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
13015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            System.Diagnostics.Process process = new System.Diagnostics.Process();
13115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.UseShellExecute = false;
13215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.FileName = "clang-format.exe";
13315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // Poor man's escaping - this will not work when quotes are already escaped
13415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // in the input (but we don't need more).
13515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            string style = GetStyle().Replace("\"", "\\\"");
13615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.Arguments = " -offset " + offset +
13715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                                          " -length " + length +
13815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                                          " -output-replacements-xml " +
13915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                                          " -style \"" + style + "\"";
14015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.CreateNoWindow = true;
14115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.RedirectStandardInput = true;
14215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.RedirectStandardOutput = true;
14315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StartInfo.RedirectStandardError = true;
14415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (path != null)
14515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                process.StartInfo.WorkingDirectory = path;
14615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // We have to be careful when communicating via standard input / output,
14715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // as writes to the buffers will block until they are read from the other side.
14815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // Thus, we:
14915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // 1. Start the process - clang-format.exe will start to read the input from the
15015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            //    standard input.
15122d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            try
15222d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            {
15322d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek                process.Start();
15422d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            }
15522d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            catch (Exception e)
15622d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            {
15722d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek                throw new Exception(
15822d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek                    "Cannot execute " + process.StartInfo.FileName + ".\n\"" +
15922d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek                    e.Message + "\".\nPlease make sure it is on the PATH.");
16022d58ddc9e3cb01ef2d736a27759cda39a336b95Manuel Klimek            }
16115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // 2. We write everything to the standard output - this cannot block, as clang-format
16215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            //    reads the full standard input before analyzing it without writing anything to the
16315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            //    standard output.
16415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StandardInput.Write(text);
16515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // 3. We notify clang-format that the input is done - after this point clang-format
16615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            //    will start analyzing the input and eventually write the output.
16715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.StandardInput.Close();
16815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // 4. We must read clang-format's output before waiting for it to exit; clang-format
16915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            //    will close the channel by exiting.
17015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            string output = process.StandardOutput.ReadToEnd();
17115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // 5. clang-format is done, wait until it is fully shut down.
17215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            process.WaitForExit();
17315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (process.ExitCode != 0)
17415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            {
17515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                // FIXME: If clang-format writes enough to the standard error stream to block,
17615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                // we will never reach this point; instead, read the standard error asynchronously.
17715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                throw new Exception(process.StandardError.ReadToEnd());
17815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            }
17915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            return output;
18015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
18115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
18215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// <summary>
18315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// Returns the currently active view if it is a IWpfTextView.
18415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        /// </summary>
18515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private IWpfTextView GetCurrentView()
18615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
18715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // The SVsTextManager is a service through which we can get the active view.
18815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            var textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));
18915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            IVsTextView textView;
19015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            textManager.GetActiveView(1, null, out textView);
19115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
19215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // Now we have the active view as IVsTextView, but the text interfaces we need
19315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            // are in the IWpfTextView.
19415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            var userData = (IVsUserData)textView;
19515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (userData == null)
19615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                return null;
19715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            Guid guidWpfViewHost = DefGuidList.guidIWpfTextViewHost;
19815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            object host;
19915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            userData.GetData(ref guidWpfViewHost, out host);
20015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            return ((IWpfTextViewHost)host).TextView;
20115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
20215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
20315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private string GetStyle()
20415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
20515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
20615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            return page.Style;
20715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
20815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek
20915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        private string GetDocumentParent(IWpfTextView view)
21015852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        {
21115852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            ITextDocument document;
21215852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            if (view.TextBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document))
21315852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            {
21415852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek                return Directory.GetParent(document.FilePath).ToString();
21515852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            }
21615852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek            return null;
21715852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek        }
21815852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek    }
21915852fc162eb6f77c28b67c868fdeeffed8c57d4Manuel Klimek}
220