PageRenderTime 838ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/Python/Product/PythonTools/PythonTools/InterpreterList/InterpreterListToolWindow.cs

https://gitlab.com/SplatoonModdingHub/PTVS
C# | 462 lines | 373 code | 65 blank | 24 comment | 44 complexity | bce06b60e8a2738f166ca2cf32dece99 MD5 | raw file
  1. // Python Tools for Visual Studio
  2. // Copyright(c) Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the License); you may not use
  6. // this file except in compliance with the License. You may obtain a copy of the
  7. // License at http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
  10. // OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
  11. // IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
  12. // MERCHANTABLITY OR NON-INFRINGEMENT.
  13. //
  14. // See the Apache Version 2.0 License for specific language governing
  15. // permissions and limitations under the License.
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.IO;
  20. using System.Linq;
  21. using System.Runtime.ExceptionServices;
  22. using System.Runtime.InteropServices;
  23. using System.Windows.Forms;
  24. using System.Windows.Input;
  25. using Microsoft.PythonTools.Debugger;
  26. using Microsoft.PythonTools.EnvironmentsList;
  27. using Microsoft.PythonTools.Infrastructure;
  28. using Microsoft.PythonTools.Interpreter;
  29. using Microsoft.PythonTools.Project;
  30. using Microsoft.PythonTools.Repl;
  31. using Microsoft.VisualStudio.Imaging;
  32. using Microsoft.PythonTools.InteractiveWindow.Shell;
  33. using Microsoft.VisualStudio.Shell;
  34. using Microsoft.VisualStudio.Shell.Interop;
  35. namespace Microsoft.PythonTools.InterpreterList {
  36. [Guid(PythonConstants.InterpreterListToolWindowGuid)]
  37. sealed class InterpreterListToolWindow : ToolWindowPane {
  38. private IServiceProvider _site;
  39. private PythonToolsService _pyService;
  40. private Redirector _outputWindow;
  41. private IVsStatusbar _statusBar;
  42. public InterpreterListToolWindow() { }
  43. protected override void OnCreate() {
  44. base.OnCreate();
  45. _site = (IServiceProvider)this;
  46. _pyService = _site.GetPythonToolsService();
  47. // TODO: Get PYEnvironment added to image list
  48. BitmapImageMoniker = KnownMonikers.DockPanel;
  49. Caption = Strings.Environments;
  50. _outputWindow = OutputWindowRedirector.GetGeneral(_site);
  51. Debug.Assert(_outputWindow != null);
  52. _statusBar = _site.GetService(typeof(SVsStatusbar)) as IVsStatusbar;
  53. var list = new ToolWindow();
  54. list.Site = _site;
  55. list.ViewCreated += List_ViewCreated;
  56. list.CommandBindings.Add(new CommandBinding(
  57. EnvironmentView.OpenInteractiveWindow,
  58. OpenInteractiveWindow_Executed,
  59. OpenInteractiveWindow_CanExecute
  60. ));
  61. list.CommandBindings.Add(new CommandBinding(
  62. EnvironmentView.OpenInteractiveScripts,
  63. OpenInteractiveScripts_Executed,
  64. OpenInteractiveScripts_CanExecute
  65. ));
  66. list.CommandBindings.Add(new CommandBinding(
  67. EnvironmentPathsExtension.StartInterpreter,
  68. StartInterpreter_Executed,
  69. StartInterpreter_CanExecute
  70. ));
  71. list.CommandBindings.Add(new CommandBinding(
  72. EnvironmentPathsExtension.StartWindowsInterpreter,
  73. StartInterpreter_Executed,
  74. StartInterpreter_CanExecute
  75. ));
  76. list.CommandBindings.Add(new CommandBinding(
  77. ApplicationCommands.Help,
  78. OnlineHelp_Executed,
  79. OnlineHelp_CanExecute
  80. ));
  81. list.CommandBindings.Add(new CommandBinding(
  82. ToolWindow.UnhandledException,
  83. UnhandledException_Executed,
  84. UnhandledException_CanExecute
  85. ));
  86. list.CommandBindings.Add(new CommandBinding(
  87. EnvironmentView.OpenInPowerShell,
  88. OpenInPowerShell_Executed,
  89. OpenInPowerShell_CanExecute
  90. ));
  91. list.CommandBindings.Add(new CommandBinding(
  92. EnvironmentView.OpenInCommandPrompt,
  93. OpenInCommandPrompt_Executed,
  94. OpenInCommandPrompt_CanExecute
  95. ));
  96. list.CommandBindings.Add(new CommandBinding(
  97. EnvironmentView.EnableIPythonInteractive,
  98. EnableIPythonInteractive_Executed,
  99. EnableIPythonInteractive_CanExecute
  100. ));
  101. list.CommandBindings.Add(new CommandBinding(
  102. EnvironmentView.DisableIPythonInteractive,
  103. DisableIPythonInteractive_Executed,
  104. DisableIPythonInteractive_CanExecute
  105. ));
  106. list.CommandBindings.Add(new CommandBinding(
  107. EnvironmentPathsExtension.OpenInBrowser,
  108. OpenInBrowser_Executed,
  109. OpenInBrowser_CanExecute
  110. ));
  111. Content = list;
  112. }
  113. private string GetScriptPath(EnvironmentView view) {
  114. if (view == null) {
  115. return null;
  116. }
  117. return PythonInteractiveEvaluator.GetScriptsPath(
  118. _site,
  119. view.Description,
  120. view.Factory.Configuration,
  121. false
  122. );
  123. }
  124. private void OpenInteractiveScripts_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  125. var path = GetScriptPath(e.Parameter as EnvironmentView);
  126. e.CanExecute = path != null;
  127. e.Handled = true;
  128. }
  129. private bool EnsureScriptDirectory(string path) {
  130. if (string.IsNullOrEmpty(path)) {
  131. return false;
  132. }
  133. if (!Directory.Exists(path)) {
  134. try {
  135. Directory.CreateDirectory(path);
  136. File.WriteAllText(PathUtils.GetAbsoluteFilePath(path, "readme.txt"), Strings.ReplScriptPathReadmeContents);
  137. } catch (Exception ex) when (!ex.IsCriticalException()) {
  138. TaskDialog.ForException(_site, ex, issueTrackerUrl: PythonConstants.IssueTrackerUrl).ShowModal();
  139. return false;
  140. }
  141. }
  142. return true;
  143. }
  144. private void OpenInteractiveScripts_Executed(object sender, ExecutedRoutedEventArgs e) {
  145. var path = GetScriptPath(e.Parameter as EnvironmentView);
  146. if (!EnsureScriptDirectory(path)) {
  147. return;
  148. }
  149. var psi = new ProcessStartInfo();
  150. psi.UseShellExecute = false;
  151. psi.FileName = "explorer.exe";
  152. psi.Arguments = "\"" + path + "\"";
  153. Process.Start(psi).Dispose();
  154. e.Handled = true;
  155. }
  156. private void EnableIPythonInteractive_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  157. var path = GetScriptPath(e.Parameter as EnvironmentView);
  158. e.CanExecute = path != null && !File.Exists(PathUtils.GetAbsoluteFilePath(path, "mode.txt"));
  159. e.Handled = true;
  160. }
  161. private void EnableIPythonInteractive_Executed(object sender, ExecutedRoutedEventArgs e) {
  162. var path = GetScriptPath(e.Parameter as EnvironmentView);
  163. if (!EnsureScriptDirectory(path)) {
  164. return;
  165. }
  166. path = PathUtils.GetAbsoluteFilePath(path, "mode.txt");
  167. try {
  168. File.WriteAllText(path, Strings.ReplScriptPathIPythonModeTxtContents);
  169. } catch (Exception ex) when (!ex.IsCriticalException()) {
  170. TaskDialog.ForException(_site, ex, issueTrackerUrl: PythonConstants.IssueTrackerUrl).ShowModal();
  171. return;
  172. }
  173. e.Handled = true;
  174. }
  175. private void DisableIPythonInteractive_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  176. var path = GetScriptPath(e.Parameter as EnvironmentView);
  177. e.CanExecute = path != null && File.Exists(PathUtils.GetAbsoluteFilePath(path, "mode.txt"));
  178. e.Handled = true;
  179. }
  180. private void DisableIPythonInteractive_Executed(object sender, ExecutedRoutedEventArgs e) {
  181. var path = GetScriptPath(e.Parameter as EnvironmentView);
  182. if (!EnsureScriptDirectory(path)) {
  183. return;
  184. }
  185. path = PathUtils.GetAbsoluteFilePath(path, "mode.txt");
  186. if (File.Exists(path)) {
  187. try {
  188. File.Delete(path);
  189. } catch (Exception ex) when (!ex.IsCriticalException()) {
  190. TaskDialog.ForException(_site, ex, issueTrackerUrl: PythonConstants.IssueTrackerUrl).ShowModal();
  191. return;
  192. }
  193. }
  194. }
  195. private void List_ViewCreated(object sender, EnvironmentViewEventArgs e) {
  196. var view = e.View;
  197. var pep = new PipExtensionProvider(view.Factory);
  198. pep.GetElevateSetting += PipExtensionProvider_GetElevateSetting;
  199. pep.OperationStarted += PipExtensionProvider_OperationStarted;
  200. pep.OutputTextReceived += PipExtensionProvider_OutputTextReceived;
  201. pep.ErrorTextReceived += PipExtensionProvider_ErrorTextReceived;
  202. pep.OperationFinished += PipExtensionProvider_OperationFinished;
  203. view.Extensions.Add(pep);
  204. var _withDb = view.Factory as PythonInterpreterFactoryWithDatabase;
  205. if (_withDb != null) {
  206. view.Extensions.Add(new DBExtensionProvider(_withDb));
  207. }
  208. var model = _site.GetComponentModel();
  209. if (model != null) {
  210. try {
  211. foreach (var provider in model.GetExtensions<IEnvironmentViewExtensionProvider>()) {
  212. try {
  213. var ext = provider.CreateExtension(view);
  214. if (ext != null) {
  215. view.Extensions.Add(ext);
  216. }
  217. } catch (Exception ex) {
  218. LogLoadException(provider, ex);
  219. }
  220. }
  221. } catch (Exception ex2) {
  222. LogLoadException(null, ex2);
  223. }
  224. }
  225. }
  226. private void LogLoadException(IEnvironmentViewExtensionProvider provider, Exception ex) {
  227. string message;
  228. if (provider == null) {
  229. message = Strings.ErrorLoadingEnvironmentViewExtensions.FormatUI(ex);
  230. } else {
  231. message = Strings.ErrorLoadingEnvironmentViewExtension.FormatUI(provider.GetType().FullName, ex);
  232. }
  233. Debug.Fail(message);
  234. var log = _site.GetService(typeof(SVsActivityLog)) as IVsActivityLog;
  235. if (log != null) {
  236. log.LogEntry(
  237. (uint)__ACTIVITYLOG_ENTRYTYPE.ALE_ERROR,
  238. Strings.ProductTitle,
  239. message
  240. );
  241. }
  242. }
  243. private void PipExtensionProvider_GetElevateSetting(object sender, ValueEventArgs<bool> e) {
  244. e.Value = _pyService.GeneralOptions.ElevatePip;
  245. }
  246. private void PipExtensionProvider_OperationStarted(object sender, ValueEventArgs<string> e) {
  247. _outputWindow.WriteLine(e.Value);
  248. if (_statusBar != null) {
  249. _statusBar.SetText(e.Value);
  250. }
  251. if (_pyService.GeneralOptions.ShowOutputWindowForPackageInstallation) {
  252. _outputWindow.ShowAndActivate();
  253. }
  254. }
  255. private void PipExtensionProvider_OutputTextReceived(object sender, ValueEventArgs<string> e) {
  256. _outputWindow.WriteLine(e.Value);
  257. }
  258. private void PipExtensionProvider_ErrorTextReceived(object sender, ValueEventArgs<string> e) {
  259. _outputWindow.WriteErrorLine(e.Value);
  260. }
  261. private void PipExtensionProvider_OperationFinished(object sender, ValueEventArgs<string> e) {
  262. _outputWindow.WriteLine(e.Value);
  263. if (_statusBar != null) {
  264. _statusBar.SetText(e.Value);
  265. }
  266. if (_pyService.GeneralOptions.ShowOutputWindowForPackageInstallation) {
  267. _outputWindow.ShowAndActivate();
  268. }
  269. }
  270. private void UnhandledException_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  271. e.CanExecute = e.Parameter is ExceptionDispatchInfo;
  272. }
  273. private void UnhandledException_Executed(object sender, ExecutedRoutedEventArgs e) {
  274. var ex = (ExceptionDispatchInfo)e.Parameter;
  275. Debug.Assert(ex != null, "Unhandled exception with no exception object");
  276. if (ex.SourceException is PipException) {
  277. // Don't report Pip exceptions. The output messages have
  278. // already been handled.
  279. return;
  280. }
  281. var td = TaskDialog.ForException(_site, ex.SourceException, String.Empty, PythonConstants.IssueTrackerUrl);
  282. td.Title = Strings.ProductTitle;
  283. td.ShowModal();
  284. }
  285. private void OpenInteractiveWindow_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  286. var view = e.Parameter as EnvironmentView;
  287. e.CanExecute = view != null &&
  288. view.Factory != null &&
  289. view.Factory.Configuration != null &&
  290. File.Exists(view.Factory.Configuration.InterpreterPath);
  291. }
  292. private void OpenInteractiveWindow_Executed(object sender, ExecutedRoutedEventArgs e) {
  293. var view = (EnvironmentView)e.Parameter;
  294. var config = view.Factory.Configuration;
  295. var replId = PythonReplEvaluatorProvider.GetEvaluatorId(config);
  296. var compModel = _site.GetComponentModel();
  297. var service = compModel.GetService<InteractiveWindowProvider>();
  298. IVsInteractiveWindow window;
  299. // TODO: Figure out another way to get the project
  300. //var provider = _service.KnownProviders.OfType<LoadedProjectInterpreterFactoryProvider>().FirstOrDefault();
  301. //var vsProject = provider == null ?
  302. // null :
  303. // provider.GetProject(factory);
  304. //PythonProjectNode project = vsProject == null ? null : vsProject.GetPythonProject();
  305. try {
  306. window = service.OpenOrCreate(replId);
  307. } catch (Exception ex) when (!ex.IsCriticalException()) {
  308. MessageBox.Show(Strings.ErrorOpeningInteractiveWindow.FormatUI(ex), Strings.ProductTitle);
  309. return;
  310. }
  311. window?.Show(true);
  312. }
  313. private void StartInterpreter_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  314. var view = e.Parameter as EnvironmentView;
  315. e.CanExecute = view != null && File.Exists(e.Command == EnvironmentPathsExtension.StartInterpreter ?
  316. view.Factory.Configuration.InterpreterPath :
  317. view.Factory.Configuration.WindowsInterpreterPath);
  318. e.Handled = true;
  319. }
  320. private void StartInterpreter_Executed(object sender, ExecutedRoutedEventArgs e) {
  321. var view = (EnvironmentView)e.Parameter;
  322. var config = new LaunchConfiguration(view.Factory.Configuration) {
  323. PreferWindowedInterpreter = (e.Command == EnvironmentPathsExtension.StartWindowsInterpreter),
  324. WorkingDirectory = view.Factory.Configuration.PrefixPath,
  325. SearchPaths = new List<string>()
  326. };
  327. var sln = (IVsSolution)_site.GetService(typeof(SVsSolution));
  328. foreach (var pyProj in sln.EnumerateLoadedPythonProjects()) {
  329. if (pyProj.InterpreterConfigurations.Contains(config.Interpreter)) {
  330. config.SearchPaths.AddRange(pyProj.GetSearchPaths());
  331. }
  332. }
  333. Process.Start(DebugLaunchHelper.CreateProcessStartInfo(_site, config)).Dispose();
  334. }
  335. private void OnlineHelp_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  336. e.CanExecute = _site != null;
  337. e.Handled = true;
  338. }
  339. private void OnlineHelp_Executed(object sender, ExecutedRoutedEventArgs e) {
  340. VisualStudioTools.CommonPackage.OpenVsWebBrowser(_site, PythonToolsPackage.InterpreterHelpUrl);
  341. e.Handled = true;
  342. }
  343. private static readonly string[] PathSuffixes = new[] { "", "Scripts" };
  344. private static string GetPathEntries(EnvironmentView view) {
  345. if (!Directory.Exists(view?.PrefixPath)) {
  346. return null;
  347. }
  348. return string.Join(";", PathSuffixes
  349. .Select(s => PathUtils.GetAbsoluteDirectoryPath(view.PrefixPath, s))
  350. .Where(Directory.Exists));
  351. }
  352. private void OpenInCommandPrompt_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  353. var view = e.Parameter as EnvironmentView;
  354. e.CanExecute = Directory.Exists(view?.PrefixPath);
  355. e.Handled = true;
  356. }
  357. private void OpenInCommandPrompt_Executed(object sender, ExecutedRoutedEventArgs e) {
  358. var view = (EnvironmentView)e.Parameter;
  359. var paths = GetPathEntries(view);
  360. var pathCmd = string.IsNullOrEmpty(paths) ? "" : string.Format("set PATH={0};%PATH% & ", paths);
  361. var psi = new ProcessStartInfo("cmd.exe");
  362. psi.Arguments = string.Join(" ", new[] {
  363. "/S",
  364. "/K",
  365. pathCmd + string.Format("title {0} environment", view.Description)
  366. }.Select(ProcessOutput.QuoteSingleArgument));
  367. psi.WorkingDirectory = view.PrefixPath;
  368. Process.Start(psi).Dispose();
  369. }
  370. private void OpenInPowerShell_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  371. var view = e.Parameter as EnvironmentView;
  372. e.CanExecute = Directory.Exists(view?.PrefixPath);
  373. e.Handled = true;
  374. }
  375. private void OpenInPowerShell_Executed(object sender, ExecutedRoutedEventArgs e) {
  376. var view = (EnvironmentView)e.Parameter;
  377. var paths = GetPathEntries(view);
  378. var pathCmd = string.IsNullOrEmpty(paths) ? "" : string.Format("$env:PATH='{0};' + $env:PATH; ", paths);
  379. var psi = new ProcessStartInfo("powershell.exe");
  380. psi.Arguments = string.Join(" ", new[] {
  381. "-NoLogo",
  382. "-NoExit",
  383. "-Command",
  384. pathCmd + string.Format("(Get-Host).UI.RawUI.WindowTitle = '{0} environment'", view.Description)
  385. }.Select(ProcessOutput.QuoteSingleArgument));
  386. psi.WorkingDirectory = view.PrefixPath;
  387. Process.Start(psi).Dispose();
  388. }
  389. private void OpenInBrowser_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
  390. e.CanExecute = e.Parameter is string;
  391. e.Handled = true;
  392. }
  393. private void OpenInBrowser_Executed(object sender, ExecutedRoutedEventArgs e) {
  394. PythonToolsPackage.OpenVsWebBrowser(_site, (string)e.Parameter);
  395. }
  396. }
  397. }