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