Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: wip AI fix #344

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,13 @@ public class LsTrust
{
public IList<string> TrustedFolders { get; set; }
}

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class ShowDocumentParams
{
public string Uri { get; set; }
public bool External { get; set; }
public bool TakeFocus{ get; set; }
public Range Selection { get; set; }
}
}
3 changes: 2 additions & 1 deletion Snyk.VisualStudio.Extension.2022/Language/LsConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public static class LsConstants
public const string SnykGetFeatureFlagStatus = "snyk.getFeatureFlagStatus";
public const string SnykGenerateIssueDescription = "snyk.generateIssueDescription";
public const string SnykReportAnalytics = "snyk.reportAnalytics";


public const string ShowDocument = "window/showDocument";
// Feature flags
public const string SnykConsistentIgnoresEnabled = "snykCodeConsistentIgnores";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,45 @@ public async Task OnSnykScan(JToken arg)
}
}

[JsonRpcMethod(LsConstants.ShowDocument)]
public async Task OnShowDocument(JToken arg)
{
var lspAnalysisResult = arg.TryParse<ShowDocumentParams>();
if (lspAnalysisResult == null) return;
var uri = new Uri(Uri.UnescapeDataString(lspAnalysisResult.Uri));

// Manually parse query parameters
var queryParams = ParseQueryString(uri.Query);
var issueId = queryParams["issueId"];
var product = LspSourceToProduct(queryParams["product"].Replace("+", " "));
var action= queryParams["action"];
if (action != "showInDetailPanel")
{
return;
}
serviceProvider.ToolWindow.SelectedItemInTree(issueId, product);
}

static Dictionary<string, string> ParseQueryString(string query)
{
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

if (query.StartsWith("?"))
query = query.Substring(1);

foreach (var pair in query.Split('&'))
{
var parts = pair.Split('=');
if (parts.Length == 2)
{
var key = Uri.UnescapeDataString(parts[0]);
var value = Uri.UnescapeDataString(parts[1]);
result[key] = value;
}
}
return result;
}

[JsonRpcMethod(LsConstants.SnykFolderConfig)]
public async Task OnFolderConfig(JToken arg)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,119 @@ private void OnIacScanningStarted(object sender, SnykCodeScanEventArgs e)
});
}

public void SelectedItemInTree(string issueId, string product)
{
ThreadHelper.JoinableTaskFactory.Run(async () =>
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

var rootNodes = new List<TreeNode>();

switch (product)
{
case Product.Code:
rootNodes.Add(this.resultsTree.CodeSecurityRootNode);
rootNodes.Add(this.resultsTree.CodeQualityRootNode);
break;
case Product.Oss:
rootNodes.Add(this.resultsTree.OssRootNode);
break;
case Product.Iac:
rootNodes.Add(this.resultsTree.IacRootNode);
break;
}

foreach (var rootNode in rootNodes)
{
var foundAndSelected = TrySelectIssueInRootNode(rootNode, issueId);
if (foundAndSelected)
{
break;
}
}
});
}

/// <summary>
/// Searches the given root node (e.g. CodeSecurityRootNode) for a child CodeTreeNode
/// whose Issue.Id matches <paramref name="issueId"/>. If found, selects it.
/// </summary>
private bool TrySelectIssueInRootNode(TreeNode rootNode, string issueId)
{
foreach (var treeItem in rootNode.Items)
{
if (treeItem is FileTreeNode fileTreeNode)
{
foreach (var childNode in fileTreeNode.Items)
{
if (childNode is IssueTreeNode issueTreeNode && issueTreeNode.Issue.Id == issueId)
{
issueTreeNode.IsSelected = true;

this.resultsTree.CurrentTreeNode = issueTreeNode;

var tvItem = FindContainerForItem(resultsTree.vulnerabilitiesTree, issueTreeNode);
if (tvItem != null)
{
tvItem.IsSelected = true;
}
if (resultsTree.vulnerabilitiesTree.SelectedItem == issueTreeNode)
{
RaiseSelectedItemChanged(resultsTree.vulnerabilitiesTree, resultsTree.vulnerabilitiesTree.SelectedItem, issueTreeNode);
}
return true;
}
}
}
}

return false;
}

public static TreeViewItem FindContainerForItem(
ItemsControl parent,
object targetItem,
bool autoExpandParents = false)
{
if (parent.ItemContainerGenerator.ContainerFromItem(targetItem) is TreeViewItem container) return container;

foreach (var childItem in parent.Items)
{
if (parent.ItemContainerGenerator.ContainerFromItem(childItem) is not TreeViewItem parentContainer)
continue;
if (autoExpandParents)
{
// Expand to force generation of deeper levels
parentContainer.IsExpanded = true;
parent.UpdateLayout();
}

// Recurse
var descendantContainer = FindContainerForItem(
parentContainer,
targetItem,
autoExpandParents);

if (descendantContainer != null)
return descendantContainer;
}
return null;
}
private void RaiseSelectedItemChanged(TreeView tree, object oldItem, object newItem)
{
// Build the args needed for the SelectedItemChanged event
var args = new RoutedPropertyChangedEventArgs<object>(
oldItem,
newItem
)
{
RoutedEvent = TreeView.SelectedItemChangedEvent,
Source = tree
};

// Manually raise the event on the TreeView
tree.RaiseEvent(args);
}
private void OnIacScanningDisabled(object sender, SnykCodeScanEventArgs e)
{
ThreadHelper.JoinableTaskFactory.Run(async () =>
Expand Down Expand Up @@ -721,6 +834,11 @@ private void VulnerabilitiesTree_SelectetVulnerabilityChanged(object sender, Rou

this.messagePanel.Visibility = Visibility.Collapsed;

if (sender is TreeViewItem item)
{
item.BringIntoView();
}

if (this.resultsTree.SelectedItem is OssTreeNode)
{
this.HandleOssTreeNodeSelected();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private void FillIssueRootNode(ISnykServiceProvider serviceProvider, IDictionary

var fileNode = TreeNodeProductFactory.GetFileTreeNode(product, rootNode);
fileNode.IssueList = issueList;
fileNode.IsExpanded = false;
fileNode.IsExpanded = true;
fileNode.FileName = kv.Key;
fileNode.FolderName = currentFolder;

Expand Down
Loading