Skip to content
Open
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
1 change: 1 addition & 0 deletions AxialSqlTools/AxialSqlTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
<Compile Include="Modules\GoogleSheetsExport.cs" />
<Compile Include="Modules\GridAccess.cs" />
<Compile Include="Modules\KeypressCommandFilter.cs" />
<Compile Include="Modules\SqlStringSelectionMouseProcessor.cs" />
<Compile Include="Modules\MetricsService.cs" />
<Compile Include="Modules\ScriptFactoryAccess.cs" />
<Compile Include="Modules\SettingsManager.cs" />
Expand Down
4 changes: 0 additions & 4 deletions AxialSqlTools/Modules/KeypressCommandFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace AxialSqlTools
Expand Down
150 changes: 150 additions & 0 deletions AxialSqlTools/Modules/SqlStringSelectionMouseProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Input;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Formatting;
using Microsoft.VisualStudio.Utilities;

namespace AxialSqlTools
{
[Export(typeof(IMouseProcessorProvider))]
[Name("sql-string-double-click-selector")]
[ContentType("text")]
[ContentType("code")]
[Order(Before = PredefinedMouseProcessorNames.WordSelection)]
[TextViewRole(PredefinedTextViewRoles.Editable)]
public class SqlStringSelectionMouseProcessorProvider : IMouseProcessorProvider
{
public IMouseProcessor GetAssociatedProcessor(IWpfTextView wpfTextView)
{
return new SqlStringSelectionMouseProcessor(wpfTextView);
}
}

public class SqlStringSelectionMouseProcessor : MouseProcessorBase
{
private readonly IWpfTextView view;

public SqlStringSelectionMouseProcessor(IWpfTextView view)
{
this.view = view ?? throw new ArgumentNullException(nameof(view));
}

public override void PreprocessMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left)
{
return;
}

if (e.ClickCount != 2)
{
return;
}

if (Keyboard.Modifiers != ModifierKeys.None)
{
return;
}

if (SelectQuotedString(e))
{
e.Handled = true;
}
}

private bool SelectQuotedString(MouseButtonEventArgs e)
{
SnapshotPoint? snapshotPoint = GetSnapshotAtCursor(e);

if (snapshotPoint.HasValue && TryGetQuotedStringSpan(snapshotPoint.Value, out SnapshotSpan span))
{
view.Selection.Select(span, isReversed: false);
view.Caret.MoveTo(span.End);
return true;
}

return false;
}

private SnapshotPoint? GetSnapshotAtCursor(MouseButtonEventArgs e)
{
if (view.TextViewLines == null || view.TextViewLines.IsEmpty)
{
return null;
}

Point cursorPosition = GetPositionInViewport(e);
ITextViewLine textViewLine = view.TextViewLines.GetTextViewLineContainingYCoordinate(cursorPosition.Y);

if (textViewLine != null)
{
return textViewLine.GetBufferPositionFromXCoordinate(cursorPosition.X, true);
}

return null;
}

private Point GetPositionInViewport(MouseButtonEventArgs e)
{
Point relativePosition = e.GetPosition(view.VisualElement);
return new Point(relativePosition.X + view.ViewportLeft, relativePosition.Y + view.ViewportTop);
}

private bool TryGetQuotedStringSpan(SnapshotPoint point, out SnapshotSpan span)
{
string text = point.Snapshot.GetText();
int position = point.Position;

bool insideString = false;
int stringStart = -1;

for (int index = 0; index < text.Length; index++)
{
char current = text[index];

if (current == '\'')
{
if (insideString)
{
if (index + 1 < text.Length && text[index + 1] == '\'')
{
index++;
continue;
}

int stringEnd = index;
if (position >= stringStart && position <= stringEnd)
{
span = new SnapshotSpan(point.Snapshot, stringStart, stringEnd - stringStart + 1);
return true;
}

insideString = false;
}
else
{
stringStart = index;
if (index > 0 && (text[index - 1] == 'N' || text[index - 1] == 'n'))
{
stringStart--;
}

insideString = true;
}
}
}

if (insideString && position >= stringStart)
{
span = new SnapshotSpan(point.Snapshot, stringStart, text.Length - stringStart);
return true;
}

span = default;
return false;
}
}
}
1 change: 1 addition & 0 deletions AxialSqlTools/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
</Prerequisites>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
</Assets>
</PackageManifest>