diff --git a/.gitignore b/.gitignore
index 2feec09..8467e85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -173,3 +173,6 @@ UpgradeLog*.htm
# Microsoft Fakes
FakesAssemblies/
+*.ide
+/.vs/slnx.sqlite
+/.vs/VSWorkspaceState.json
diff --git a/EasyMotion/EasyMotion.vsct b/EasyMotion/EasyMotion.vsct
index cda51e6..0328a0a 100644
--- a/EasyMotion/EasyMotion.vsct
+++ b/EasyMotion/EasyMotion.vsct
@@ -14,14 +14,40 @@
+
+
+
+
+
+
@@ -40,6 +66,9 @@
+
+
+
diff --git a/EasyMotion/EasyMotionPackage.cs b/EasyMotion/EasyMotionPackage.cs
index e95fc09..7423490 100644
--- a/EasyMotion/EasyMotionPackage.cs
+++ b/EasyMotion/EasyMotionPackage.cs
@@ -53,16 +53,23 @@ protected override void Initialize()
_exportProvider = _componentModel.DefaultExportProvider;
// Add our command handlers for menu (commands must exist in the .vsct file)
- OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
+ var mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
- // Create the command for the menu item.
- CommandID menuCommandID = new CommandID(GuidList.guidEasyMotionCmdSet, (int)PkgCmdIDList.CmdEasyMotionNavigate);
- MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
- mcs.AddCommand( menuItem );
+ AddCommand(PkgCmdIDList.CmdEasyMotionNavigate, mcs);
+ AddCommand(PkgCmdIDList.CmdEasyMotionNavigateWord, mcs);
+ AddCommand(PkgCmdIDList.CmdEasyMotionNavigateExtend, mcs);
+ AddCommand(PkgCmdIDList.CmdEasyMotionNavigateWordExtend, mcs);
}
}
+ private void AddCommand(uint cmd, OleMenuCommandService mcs)
+ {
+ var menuCommandID = new CommandID(GuidList.guidEasyMotionCmdSet, (int)cmd);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ mcs.AddCommand(menuItem);
+ }
+
private void MenuItemCallback(object sender, EventArgs e)
{
ITextView textView;
@@ -81,7 +88,25 @@ private void MenuItemCallback(object sender, EventArgs e)
}
else
{
- easyMotionUtil.ChangeToLookingForChar();
+ var command = sender as MenuCommand;
+ Debug.Assert(command != null);
+ var mode = EasyMotionSearchMode.Char;
+ switch (command.CommandID.ID)
+ {
+ case (int)PkgCmdIDList.CmdEasyMotionNavigate:
+ mode = EasyMotionSearchMode.Char;
+ break;
+ case (int)PkgCmdIDList.CmdEasyMotionNavigateWord:
+ mode = EasyMotionSearchMode.Word;
+ break;
+ case (int)PkgCmdIDList.CmdEasyMotionNavigateExtend:
+ mode = EasyMotionSearchMode.CharExtend;
+ break;
+ case (int)PkgCmdIDList.CmdEasyMotionNavigateWordExtend:
+ mode = EasyMotionSearchMode.WordExtend;
+ break;
+ }
+ easyMotionUtil.ChangeToLookingForChar(mode);
}
}
diff --git a/EasyMotion/IEasyMotionUtil.cs b/EasyMotion/IEasyMotionUtil.cs
index 12e972a..28e8a89 100644
--- a/EasyMotion/IEasyMotionUtil.cs
+++ b/EasyMotion/IEasyMotionUtil.cs
@@ -7,6 +7,31 @@
namespace EasyMotion
{
+ internal enum EasyMotionSearchMode
+ {
+ ///
+ /// Developer is looking for characters anywhere
+ ///
+ Char,
+
+ ///
+ /// Developer is looking for words starting with the typed character
+ ///
+ Word,
+
+ ///
+ /// Same as Char + extending the selection
+ ///
+ CharExtend,
+
+ ///
+ /// Same as Word + extending the selection
+ ///
+ WordExtend
+ }
+
+
+
internal enum EasyMotionState
{
///
@@ -37,6 +62,8 @@ internal interface IEasyMotionUtil
EasyMotionState State { get; }
+ EasyMotionSearchMode SearchMode { get; }
+
///
/// During the LookingForDecision state this will be the character which
/// the user has decided to make an easy motion for
@@ -47,11 +74,13 @@ internal interface IEasyMotionUtil
void ChangeToDisabled();
- void ChangeToLookingForChar();
+ void ChangeToLookingForChar(EasyMotionSearchMode searchMode);
void ChangeToLookingForDecision(char target);
void ChangeToLookingCharNotFound();
+
+ bool IsInWordMode { get; }
}
internal interface IEasyMotionUtilProvider
diff --git a/EasyMotion/Implementation/Adornment/EasyMotionAdornmentController.cs b/EasyMotion/Implementation/Adornment/EasyMotionAdornmentController.cs
index 4a786a2..c483f58 100644
--- a/EasyMotion/Implementation/Adornment/EasyMotionAdornmentController.cs
+++ b/EasyMotion/Implementation/Adornment/EasyMotionAdornmentController.cs
@@ -10,6 +10,7 @@
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using System.Windows;
+using Microsoft.VisualStudio.Text.Operations;
namespace EasyMotion.Implementation.Adornment
{
@@ -24,16 +25,21 @@ internal sealed class EasyMotionAdornmentController : IEasyMotionNavigator
private readonly IWpfTextView _wpfTextView;
private readonly IEditorFormatMap _editorFormatMap;
private readonly IClassificationFormatMap _classificationFormatMap;
+ private readonly ITextSearchService _TextSerachService;
+ private readonly IEditorOperations _editorOperations;
private readonly Dictionary _navigateMap = new Dictionary();
private readonly object _tag = new object();
private IAdornmentLayer _adornmentLayer;
- internal EasyMotionAdornmentController(IEasyMotionUtil easyMotionUtil, IWpfTextView wpfTextview, IEditorFormatMap editorFormatMap, IClassificationFormatMap classificationFormatMap)
+ internal EasyMotionAdornmentController(IEasyMotionUtil easyMotionUtil, IWpfTextView wpfTextview, IEditorFormatMap editorFormatMap, IClassificationFormatMap classificationFormatMap
+ , ITextSearchService textSerachService, IEditorOperations editorOperations)
{
_easyMotionUtil = easyMotionUtil;
_wpfTextView = wpfTextview;
_editorFormatMap = editorFormatMap;
_classificationFormatMap = classificationFormatMap;
+ _TextSerachService = textSerachService;
+ _editorOperations = editorOperations;
}
internal void SetAdornmentLayer(IAdornmentLayer adornmentLayer)
@@ -102,18 +108,33 @@ private void AddAdornments()
var endPoint = textViewLines.LastVisibleLine.End;
var snapshot = startPoint.Snapshot;
int navigateIndex = 0;
- for (int i = startPoint.Position; i < endPoint.Position; i++)
+
+ if (_easyMotionUtil.IsInWordMode && !char.IsLetterOrDigit(_easyMotionUtil.TargetChar))
{
- var point = new SnapshotPoint(snapshot, i);
+ _easyMotionUtil.ChangeToLookingCharNotFound();
+ return;
+ }
+ var toSearch = _easyMotionUtil.TargetChar.ToString();
+ var data = new FindData()
+ {
+ SearchString = _easyMotionUtil.IsInWordMode ? @"\b" + toSearch : toSearch,
+ TextSnapshotToSearch = snapshot,
+ FindOptions = _easyMotionUtil.IsInWordMode ? FindOptions.UseRegularExpressions : FindOptions.None
+ };
- if (Char.ToLower(point.GetChar()) == Char.ToLower(_easyMotionUtil.TargetChar) && navigateIndex < NavigationKeys.Length)
+ var startindex = startPoint.Position;
+ while (navigateIndex < NavigationKeys.Length)
+ {
+ var res = _TextSerachService.FindNext(startindex, false, data);
+ if (!res.HasValue || res.Value.Start.Position > endPoint.Position)
{
- string key = NavigationKeys[navigateIndex];
- navigateIndex++;
- AddNavigateToPoint(textViewLines, point, key);
+ break;
}
+ var key = NavigationKeys[navigateIndex];
+ AddNavigateToPoint(textViewLines, res.Value.Start, key);
+ startindex = res.Value.Start.Position + 1;
+ navigateIndex++;
}
-
if (navigateIndex == 0)
{
_easyMotionUtil.ChangeToLookingCharNotFound();
@@ -156,7 +177,14 @@ public bool NavigateTo(string key)
return false;
}
- _wpfTextView.Caret.MoveTo(point);
+ if (_easyMotionUtil.SearchMode == EasyMotionSearchMode.CharExtend || _easyMotionUtil.SearchMode == EasyMotionSearchMode.WordExtend)
+ {
+ _editorOperations.ExtendSelection(point.Position);
+ }
+ else
+ {
+ _wpfTextView.Caret.MoveTo(point);
+ }
return true;
}
}
diff --git a/EasyMotion/Implementation/Adornment/EasyMotionAdornmentFactory.cs b/EasyMotion/Implementation/Adornment/EasyMotionAdornmentFactory.cs
index 563d803..0c6bcf3 100644
--- a/EasyMotion/Implementation/Adornment/EasyMotionAdornmentFactory.cs
+++ b/EasyMotion/Implementation/Adornment/EasyMotionAdornmentFactory.cs
@@ -1,4 +1,5 @@
-using System;
+using Microsoft.VisualStudio.Text.Operations;
+using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
@@ -25,6 +26,8 @@ internal sealed class EasyMotionAdornmentFactory : IWpfTextViewCreationListener,
private readonly IEasyMotionUtilProvider _easyMotionUtilProvider;
private readonly IEditorFormatMapService _editorFormatMapService;
private readonly IClassificationFormatMapService _classificationFormatMapService;
+ private readonly ITextSearchService _textSerachService;
+ private readonly IEditorOperationsFactoryService _editorOperationsFactory;
#pragma warning disable 169
[Export(typeof(AdornmentLayerDefinition))]
@@ -34,11 +37,14 @@ internal sealed class EasyMotionAdornmentFactory : IWpfTextViewCreationListener,
#pragma warning restore 169
[ImportingConstructor]
- internal EasyMotionAdornmentFactory(IEasyMotionUtilProvider easyMotionUtilProvider, IEditorFormatMapService editorFormatMapService, IClassificationFormatMapService classificationFormatMapService)
+ internal EasyMotionAdornmentFactory(IEasyMotionUtilProvider easyMotionUtilProvider, IEditorFormatMapService editorFormatMapService
+ , IClassificationFormatMapService classificationFormatMapService, ITextSearchService textSearchService, IEditorOperationsFactoryService editorOperations)
{
_easyMotionUtilProvider = easyMotionUtilProvider;
_editorFormatMapService = editorFormatMapService;
_classificationFormatMapService = classificationFormatMapService;
+ _textSerachService = textSearchService;
+ _editorOperationsFactory = editorOperations;
}
private EasyMotionAdornmentController GetOrCreate(IWpfTextView wpfTextView)
@@ -50,7 +56,7 @@ private EasyMotionAdornmentController GetOrCreate(IWpfTextView wpfTextView)
var easyMotionUtil = _easyMotionUtilProvider.GetEasyMotionUtil(wpfTextView);
var editorFormatMap = _editorFormatMapService.GetEditorFormatMap(wpfTextView);
var classificationFormatMap = _classificationFormatMapService.GetClassificationFormatMap(wpfTextView);
- return new EasyMotionAdornmentController(easyMotionUtil, wpfTextView, editorFormatMap, classificationFormatMap);
+ return new EasyMotionAdornmentController(easyMotionUtil, wpfTextView, editorFormatMap, classificationFormatMap, _textSerachService, _editorOperationsFactory.GetEditorOperations(wpfTextView));
});
}
diff --git a/EasyMotion/Implementation/EasyMotionUtil/EasyMotionUtil.cs b/EasyMotion/Implementation/EasyMotionUtil/EasyMotionUtil.cs
index 46f8b77..dd55031 100644
--- a/EasyMotion/Implementation/EasyMotionUtil/EasyMotionUtil.cs
+++ b/EasyMotion/Implementation/EasyMotionUtil/EasyMotionUtil.cs
@@ -11,6 +11,7 @@ internal sealed class EasyMotionUtil : IEasyMotionUtil
{
private readonly ITextView _textView;
private EasyMotionState _state;
+ private EasyMotionSearchMode _searchMode;
private char _targetChar;
public EasyMotionState State
@@ -18,6 +19,11 @@ public EasyMotionState State
get { return _state; }
}
+ public EasyMotionSearchMode SearchMode
+ {
+ get { return _searchMode; }
+ }
+
public char TargetChar
{
get { return _targetChar; }
@@ -28,6 +34,8 @@ public ITextView TextView
get { return _textView; }
}
+ public bool IsInWordMode => SearchMode == EasyMotionSearchMode.Word || SearchMode == EasyMotionSearchMode.WordExtend;
+
public event EventHandler StateChanged;
internal EasyMotionUtil(ITextView textView)
@@ -43,9 +51,10 @@ public void ChangeToDisabled()
RaiseStateChanged();
}
- public void ChangeToLookingForChar()
+ public void ChangeToLookingForChar(EasyMotionSearchMode mode)
{
_state = EasyMotionState.LookingForChar;
+ _searchMode = mode;
_targetChar = (char)0;
RaiseStateChanged();
}
diff --git a/EasyMotion/PkgCmdID.cs b/EasyMotion/PkgCmdID.cs
index 46690e4..4f22b08 100644
--- a/EasyMotion/PkgCmdID.cs
+++ b/EasyMotion/PkgCmdID.cs
@@ -6,8 +6,10 @@ namespace EasyMotion
{
static class PkgCmdIDList
{
- public const uint CmdEasyMotionNavigate = 0x100;
+ public const uint CmdEasyMotionNavigate = 0x100;
+ public const uint CmdEasyMotionNavigateWord = 0x101;
+ public const uint CmdEasyMotionNavigateExtend = 0x102;
+ public const uint CmdEasyMotionNavigateWordExtend = 0x103;
-
- };
+ };
}
\ No newline at end of file