Implementing Find References in Visual Studio 2010 Language Service - c#

I'm implementing a Visual Studio Language Service for a custom scripting language. I've managed to implement syntax highlighting, error checking, code completion, and "Go To Definition". I am having trouble figuring out how to hook in to the "Find All References" menu option (or even get it to display at this point).
Can anyone point me to a useful resource for implementing "Find All References" functionality in Visual Studio for a custom language? I've tried Googling for any information on it, but I can't seem to find anything.

First of all, there are multiple locations where Find All References can be invoked. The primary ones are:
By right clicking on a node in Class View.
By right clicking within the text editor.
Others include:
The Call Hierarchy
Getting Started
In the ideal implementation, you'll have an implementation of IVsSimpleLibrary2 which integrates support for your language into the Class View and Object Browser windows. The implementation of Find All References centers around the IVsFindSymbol interface, which is provided by Visual Studio. Your code handles the relevant searches in the implementation of IVsSimpleLibrary2.GetList2.
Supporting right clicking on a node in Class View
Make sure your library capabilities includes _LIB_FLAGS2.LF_SUPPORTSLISTREFERENCES.
In your handler for IVsSimpleLibrary2.GetList2, you are interested in the case where all of the following are true.
pobSrch is a non-null array of length 1. I'll assume the first element is assigned to the local variable criteria for the remainder of these conditions.
criteria.eSrchType == VSOBSEARCHTYPE.SO_ENTIREWORD
criteria.grfOptions has the flag _VSOBSEARCHOPTIONS.VSOBSO_LOOKINREFS
criteria.grfOptions has the flag _VSOBSEARCHOPTIONS.VSOBSO_CASESENSITIVE
When the above conditions are met, return an IVsSimpleObjectList2 implementation whose children are lazily computed results of a Find All References command.
Supporting the Text Editor Command
In your ViewFilter.QueryCommandStatus implementation, when guidCmdGroup == VSConstants.GUID_VSStandardCommandSet97 and nCmdId == VSStd97CmdID.FindReferences you need to return OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED.
In Visual Studio 2005, note that nCmdId will be VSStd2KCmdID.FindReferences but the guidCmdGroup will be the same as mentioned before. This mismatch was corrected starting in Visual Studio 2008, after which point VSStd2KCmdID.FindReferences was no longer used.
Override ViewFilter.HandlePreExec for the case of the command GUID and ID listed above, and execute the following code for that case:
HandleFindReferences();
return true;
Add the following extension method class:
public static class IVsFindSymbolExtensions
{
public static void DoSearch(this IVsFindSymbol findSymbol, Guid symbolScope, VSOBSEARCHCRITERIA2 criteria)
{
if (findSymbol == null)
throw new ArgumentNullException("findSymbol");
VSOBSEARCHCRITERIA2[] criteriaArray = { criteria };
ErrorHandler.ThrowOnFailure(findSymbol.DoSearch(ref symbolScope, criteriaArray));
}
}
Add the following method to your ViewFilter class:
public virtual void HandleFindReferences()
{
int line;
int col;
// Get the caret position
ErrorHandler.ThrowOnFailure( TextView.GetCaretPos( out line, out col ) );
// Get the tip text at that location.
Source.BeginParse(line, col, new TokenInfo(), ParseReason.Autos, TextView, HandleFindReferencesResponse);
}
// this can be any constant value, it's just used in the next step.
public const int FindReferencesResults = 100;
void HandleFindReferencesResponse( ParseRequest req )
{
if ( req == null )
return;
// make sure the caret hasn't moved
int line;
int col;
ErrorHandler.ThrowOnFailure( TextView.GetCaretPos( out line, out col ) );
if ( req.Line != line || req.Col != col )
return;
IVsFindSymbol findSymbol = CodeWindowManager.LanguageService.GetService(typeof(SVsObjectSearch)) as IVsFindSymbol;
if ( findSymbol == null )
return;
// TODO: calculate references as an IEnumerable<IVsSimpleObjectList2>
// TODO: set the results on the IVsSimpleLibrary2 (used as described below)
VSOBSEARCHCRITERIA2 criteria =
new VSOBSEARCHCRITERIA2()
{
dwCustom = FindReferencesResults,
eSrchType = VSOBSEARCHTYPE.SO_ENTIREWORD,
grfOptions = (uint)_VSOBSEARCHOPTIONS2.VSOBSO_LISTREFERENCES,
pIVsNavInfo = null,
szName = "Find All References"
};
findSymbol.DoSearch(new Guid(SymbolScopeGuids80.All), criteria);
}
Update your implementation of IVsSimpleLibrary2.GetList2. When the search criteria's dwCustom value is set to FindReferencesResults, rather than compute the results of a Find All References command on a Class View or Object Browser node, you only need to return an IVsSimpleObjectList2 that wraps the results previously calculated by your HandleFindReferencesResponse method.

Related

Visual Studio - inserting multi-line expressions into Watch Window while debugging

While debugging in Visual Studio, how can I insert multi-line expressions into Watch Window, so that each line is not broken into a separate INVALID watch expression. This is really frustrating because I have many expressions spanning multiple lines that I need to watch. Note that both Pin to Source and Immediate Window do not work for tracking multiple values from many places in source code.
e.g.
PyFunc1(Py.kw("var1", var1),
Py.kw("var2", var2))
gets broken to:
PyFunc1(Py.kw("var1", var1),
and
Py.kw("var2", var2))
Repro
I dont think this is "By-Design", its just unavailable "out-of-the-box".
I agree, it'd be better behaviour for multi-line calls to be added to the Watch Window using line terminators instead of new lines:
Research
I found this similar question with a few "workarounds" to choose from:
Multi-Line Watch Window in Visual Studio 2010?
I also found this comment in the MSDN Forums by a MSFT Engineer:
I’m afraid that it is not supported, we often edit them one by one. Maybe you could submit this feature request: http://visualstudio.uservoice.com/forums/121579-visual-studio
Roll your own Visual Studio Add-In
So I had a go at it myself, this is by no means production code but it shows you how to do it:
(click image to enlarge)
namespace AddinMultiLineWatch
{
public class Connect : IDTExtensibility2, IDTCommandTarget
{
//ADD THESE MEMBER VARIABLES
//private DebuggerEvents _debuggerEvents = null;
//private _dispDebuggerEvents_OnEnterBreakModeEventHandler DebuggerEvents_OnEnterBreakMode;
private Window _watchWindow = null;
private CommandEvents _objCommandEvents;
private bool _isRecursive = false;
public Connect()
{
}
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
//SET THE MEMBER VARIABLES
//_debuggerEvents = _applicationObject.Events.DebuggerEvents;
//_debuggerEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(BreakHandler);
//var watchWindow = _applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindWatch);
_objCommandEvents = _applicationObject.Events.CommandEvents;
_objCommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(BeforeExecute);
if(connectMode == ext_ConnectMode.ext_cm_UISetup)
{
object []contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject.Commands;
string toolsMenuName = "Tools";
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];
ar:
CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;
try
{
Command command = commands.AddNamedCommand2(_addInInstance, "AddinMultiLineWatch", "AddinMultiLineWatch", "Executes the command for AddinMultiLineWatch", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
if((command != null) && (toolsPopup != null))
{
command.AddControl(toolsPopup.CommandBar, 1);
}
}
catch(System.ArgumentException)
{
}
}
}
//ADD THIS METHOD TO INTERCEPT THE DEBUG.ADDWATCH COMMAND
public void BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
EnvDTE.Command objCommand = default(EnvDTE.Command);
try
{
objCommand = _applicationObject.Commands.Item(Guid, ID);
}
catch (Exception ex)
{
}
if ((objCommand != null))
{
if (objCommand.Name == "Debug.AddWatch")
{
//if (_isRecursive) return;
//_isRecursive = true;
TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;
//TODO make selection goto next semi-colon/Line Terminator...
var selText = selection.Text;
if (string.IsNullOrEmpty(selText)) return;
//Only intercept multi-line Add Watch commands
if (selText.Contains(Environment.NewLine))
{
//THE BLACK MAGIC: make it fit in one line! lol
selText = selText.Replace(Environment.NewLine, string.Empty);
//THIS CALL IS RECURSIVE, I'LL LEAVE IT TO THE READER AS AN EXERCISE TO SOLVE..
_applicationObject.ExecuteCommand("Debug.AddWatch", selText);
}
}
}
}
Create a New Project > Other Project Types > Extensibility > Visual Studio Add-In > name it AddinMultiLineWatch
Go through the wizard
Add the code above to the Connect.cs class - see my //UPPERCASE comments with what stuff to add.
Put a break point on the line TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;
Press F5 and a new instance of VS will launch > choose New Project > Console App > name it TestMultilineAddWatch
In the program.cs of the Console App, specify a code call over 2 lines and put a break point on it, as shown in the screenshot, eg:
Add(1, //Breakpoint here and select both lines
2);
}
static int Add(int i, int j)
{
return i + j;
}
F5 in the TestMultilineAddWatch solution and when the code control halts on the break point > select/highlight the two lines Add(1, \r\n 2) > right click > Add Watch
Clicking Add Watch in the VS IDE debugging context menu causes the VS AddinMultiLineWatch solution to intercept the call and activate, halting on the break point.... where you will see the black magic of replacing multi lined code in to a single line sent to the Watch Window.
The Visual Studio EXEC command calling itself makes this method recursive, if you debug it, exiting out of the recursion manually you will see the results as per my screenshot.
Happy debugging!
You could do it using autohotkey and a custom key binding ( e.g. Alt+Shift+V)
!+v means Alt+Shift+v
The macro below:
If in devenv.exe, and you press Alt+Shift+V, edit the clipboard contents, removing /r/n and replace them with nothing, then press Ctrl+V to paste
I tested this out cutting and pasting in a text document in visual studio.
#IfWinActive ahk_exe devenv.exe
!+v::
FixString = %clipboard%
StringReplace, FixString, FixString,`r`n,,A
Clipboard := FixString
Send, ^v

button over button

I have a problem in my winform c# project.
In my project I have two main functions, one makes buttons at run time and the other function allows me to move the button on the form at run time. Now what can I do if I have button on other button so I made function that replace the button places as it was at the beginning but the function make problems if someone can help me it will be great!
public void upandunder(Button cBtn1, Button cBtn2)
{
if ((cBtn1.Location.X == cBtn2.Location.X) && (cBtn1.Location.Y == cBtn2.Location.Y))
{
int placex = cBtn1.Location.X;
int placey = cBtn1.Location.Y;
cBtn1.Location.X = cBtn2.Location.Y;
cBtn1.Location.Y = cBtn2.Location.Y;
cBtn2.Location.X = placex;
cBtn2.Location.Y = placey;
}
}
its makes me that errorError 1 Cannot modify the return value of 'System.Windows.Forms.Control.Location' because it is not a variable
Correct, the return value of the Location property is not editable. According to the documentation:
Because the Point class is a value type (Structure in Visual Basic, struct in Visual C#), it is returned by value, meaning accessing the property returns a copy of the upper-left point of the control. So, adjusting the X or Y properties of the Point returned from this property will not affect the Left, Right, Top, or Bottom property values of the control. To adjust these properties set each property value individually, or set the Location property with a new Point.
Therefore, you need to rewrite your code to the following:
(Also, I strongly recommend naming the parameters something other than x and y, since you're dealing with coordinates that have x and y values within the function...)
public void upandunder(Button btn1, Button btn2)
{
if ((btn1.Location.X == btn2.Location.X) && (btn1.Location.Y == btn2.Location.Y))
{
Point originalLocation = btn1.Location;
btn1.Location = btn2.Location;
btn2.Location = originalLocation;
}
}
or even better, just compare the two Point values as returned by the Location property (the Point structure overloads the == operator):
public void upandunder(Button btn1, Button btn2)
{
if (btn1.Location == btn2.Location)
{
Point originalLocation = btn1.Location;
btn1.Location = btn2.Location;
btn2.Location = originalLocation;
}
}
Of course, I fail to see how that accomplishes anything. First you check to see that the buttons are positioned on top of each other (have exactly the same x- and y-coordinates), and then if they do, you swap their positions. They're already in the same positions—you tested that before you executed the swapping code.
Judging by the name of your function (upandunder, which should be UpAndUnder following standard .NET naming conventions), it seems as if you wish to change the Z order of the buttons. If that's the case, then you should call either the BringToFront or SendToBack methods of the button control.
The Location Property on a Control returns a Point. The Point structure has the X and Y values you're working with. Instead of accessing them directly, I think you want to provide new Location points.
Give this a try (It works on my Machine)
public void UpAndUnder(Button cBtn1, Button cBtn2)
{
if (cBtn1.Location == cBtn2.Location.Y)
{
Point oldPoint = new Point(cBtn1.Location.X, cBtn1.Location.Y);
cBtn1.Location = new Point(cBtn2.Location.X, cBtn2.Location.Y);
cBtn2.Location = oldPoint;
}
}
If you want to place one button over other, just call
button1.BringToFront();
this will change Z-order of button1 and place it over all other controls.

Why does MonoTouch.Dialog use public fields for some Element options, and public properties for others

I am trying to get a StringElement's 'Value' to update in the UI when I set it after already setting up the DVC.
e.g:
public partial class TestDialog : DialogViewController
{
public TestDialog() : base (UITableViewStyle.Grouped, null)
{
var stringElement = new StringElement("Hola");
stringElement.Value = "0 Taps";
int tapCount = 0;
stringElement.Tapped += () => stringElement.Value = ++tapCount + " Taps";
Root = new RootElement("TestDialog")
{
new Section("First Section")
{
stringElement,
},
};
}
}
However the StringElement.Value is just a public field, and is only written to the UICell during initialization when Element.GetCell is called.
Why isn't it a property, with logic in the setter to update the UICell (like the majority of Elements, e.g. EntryElement.Value):
public string Value
{
get { return val; }
set
{
val = value;
if (entry != null)
entry.Text = value;
}
}
EDIT :
I made my own version of StringElement, derived from Element (basically just copied the source code from here verbatim)
I then changed it to take a class scoped reference to the cell created in GetCell, rather than function scoped. Then changed the Value field to a property:
public string Value
{
get { return val; }
set
{
val = value;
if (cell != null)
{
// (The below is copied direct from GetCell)
// The check is needed because the cell might have been recycled.
if (cell.DetailTextLabel != null)
cell.DetailTextLabel.Text = Value == null ? "" : Value;
}
}
}
It works in initial testing. However I am not sure on whether taking a reference to the cell is allowed, none of the other elements seem to do it (they only take references to control's placed within the cells). Is it possible that multiple 'live'* cell's are created based on the one MonoTouch.Dialog.Element instance?
*I say live to indicate cells currently part of the active UI. I did notice when navigating back to the dialog from a child dialog the GetCell method is invoked again and a new cell created based on the Element, but this is still a 1-1 between the element and the live cell.
For the main question:
Why does MonoTouch.Dialog use public fields for some Element options, and public properties for others?
I've been through the code, and I don't think there's a consistent reason for use of either.
The Dialog project was not part of the MonoTouch project initially - I don't think Miguel knew how useful it was going to turn out when he started wrote and grew it - I think he was more focussed on writing other apps like TweetStation at the time.
I know of several people (including me!) who have branched the code and adapted it for their purposes. I would guess at some future point Xamarin might write a 2.0 version with stricter coding standards.
Taking references to live cells
For limited use you can do this... but in general don't.
The idea of the table view is that cells get reused when the user scrolls up and down - especially in order to save memory and ui resources. Because of this is a long list, multiple elements might get references to the same cell.
If you do want to cache a cell reference then you probably should override GetCell() so that it never tries to reuse existing cells (never calls DequeueReusableCell)
Alternatively, you could try to change some code in the base Element class in order to find out if the Element has a current attached cell - this is what CurrentAttachedCell does in my branch of Dialog https://github.com/slodge/MvvmCross/blob/master/Cirrious/Cirrious.MvvmCross.Dialog/Dialog/Elements/Element.cs (but that branch has other added functions and dependencies so you probably won't want to use it for this current work!)

How to write an add-in to change text color in Visual Studio editor?

After searching for a long time for a simple way of changing the text color of a #region directive in Visual Studio, I've concluded there is no easy way of doing so.
I know how to change the #region statement color, and how to change the collapsed region color, but I want to change the color of the text with the region description. So:
#region Some text <--- all this text should be in a different color
public void Test()
{
}
#endregion <--- this too
It seems a lot of people are looking for something like this - see How to change the color of expanded regions' titles in VS2008?.
So I've been looking at writing a simple Visual Studio add-in to change the color.
However, it's more complicated than I thought it would be, with classes like Snapshot, Tagger, Classifier, WpfTextViewCreationListener, AdornmentLayer etc.
Simply put, I don't know where to start! I followed a couple of tutorials at the MSDN site, but they seem too complicated for what I'm trying to do.
Can someone point me to the most simple way of doing this? Ie. which classes/methods/events within the VS SDK I should use. I don't mind if the color is not customisable via the UI etc either. I'm using VS2010.
Edit: Just had the mztools website recommended to me; I'll take a look there too. Also noticed that StackOverflow's syntax highlighting of regions is pretty much exactly what I want!
I eventually came up with a solution, at least for VS2010.
Whilst I have used this for coloring '#region' and '#endregion' tags, a similar solution ought to be applicable for any text content in a Visual Studio window.
It seems that this sort of problem can be resolved by creating a IViewTaggerProvider which will 'tag' parts of the source code with a 'classification'.
Visual Studio will provide a style for text tagged with that classification which can then be changed by the user to the desired style via Tools > Options... > Environment > Fonts and Colors.
The Tagger provider looks like:
[Export(typeof(IViewTaggerProvider))]
[ContentType("any")]
[TagType(typeof(ClassificationTag))]
public sealed class RegionTaggerProvider : IViewTaggerProvider
{
[Import]
public IClassificationTypeRegistryService Registry;
[Import]
internal ITextSearchService TextSearchService { get; set; }
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
{
if (buffer != textView.TextBuffer)
return null;
var classType = Registry.GetClassificationType("region-foreground");
return new RegionTagger(textView, TextSearchService, classType) as ITagger<T>;
}
}
This creates an ITagger object, which, given a Visual Studio text view, will tag parts of the text with the given classification type. Note that this will work for all text views (i.e. source code editor, 'Find Results' windows etc.). It may be possible to change this by editing the ContentType attribute (to just C#?).
The classification type (in this case "region-foreground") is defined as:
public static class TypeExports
{
[Export(typeof(ClassificationTypeDefinition))]
[Name("region-foreground")]
public static ClassificationTypeDefinition OrdinaryClassificationType;
}
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "region-foreground")]
[Name("region-foreground")]
[UserVisible(true)]
[Order(After = Priority.High)]
public sealed class RegionForeground : ClassificationFormatDefinition
{
public RegionForeground()
{
DisplayName = "Region Foreground";
ForegroundColor = Colors.Gray;
}
}
The Order attribute determines when the classification will be applied compared to other classifications which may also apply to a span of text.
The DisplayName will be used in the Tools > Options... dialog.
Once the classification is defined, an ITagger class can search a view's text and provide classifications for applicable sections of the text it finds.
Simply put, its job is to listen for the ViewLayoutChanged event of the text view, which is fired when the provided text view's content changes (e.g. because the the user has typed something).
It must then search the text for the area of text it is interested in (called a 'span'). Here, it returns spans of lines containing either #region or #endregion. I've kept this simple, but the TextSearchService used to find matches can also search using regular expressions.
Finally, a method is provided for Visual Studio to retrieve the tags of the text it has found, called GetTags(). For a given span collection, this will return text spans with classification tags, i.e. areas of those spans which should be classified in a certain way.
Its code is:
public sealed class RegionTagger : ITagger<ClassificationTag>
{
private readonly ITextView m_View;
private readonly ITextSearchService m_SearchService;
private readonly IClassificationType m_Type;
private NormalizedSnapshotSpanCollection m_CurrentSpans;
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
public RegionTagger(ITextView view, ITextSearchService searchService, IClassificationType type)
{
m_View = view;
m_SearchService = searchService;
m_Type = type;
m_CurrentSpans = GetWordSpans(m_View.TextSnapshot);
m_View.GotAggregateFocus += SetupSelectionChangedListener;
}
private void SetupSelectionChangedListener(object sender, EventArgs e)
{
if (m_View != null)
{
m_View.LayoutChanged += ViewLayoutChanged;
m_View.GotAggregateFocus -= SetupSelectionChangedListener;
}
}
private void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
if (e.OldSnapshot != e.NewSnapshot)
{
m_CurrentSpans = GetWordSpans(e.NewSnapshot);
TagsChanged(this, new SnapshotSpanEventArgs(new SnapshotSpan(e.NewSnapshot, 0, e.NewSnapshot.Length)));
}
}
private NormalizedSnapshotSpanCollection GetWordSpans(ITextSnapshot snapshot)
{
var wordSpans = new List<SnapshotSpan>();
wordSpans.AddRange(FindAll(#"#region", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
wordSpans.AddRange(FindAll(#"#endregion", snapshot).Select(regionLine => regionLine.Start.GetContainingLine().Extent));
return new NormalizedSnapshotSpanCollection(wordSpans);
}
private IEnumerable<SnapshotSpan> FindAll(String searchPattern, ITextSnapshot textSnapshot)
{
if (textSnapshot == null)
return null;
return m_SearchService.FindAll(
new FindData(searchPattern, textSnapshot) {
FindOptions = FindOptions.WholeWord | FindOptions.MatchCase
});
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (spans == null || spans.Count == 0 || m_CurrentSpans.Count == 0)
yield break;
ITextSnapshot snapshot = m_CurrentSpans[0].Snapshot;
spans = new NormalizedSnapshotSpanCollection(spans.Select(s => s.TranslateTo(snapshot, SpanTrackingMode.EdgeExclusive)));
foreach (var span in NormalizedSnapshotSpanCollection.Intersection(m_CurrentSpans, spans))
{
yield return new TagSpan<ClassificationTag>(span, new ClassificationTag(m_Type));
}
}
}
For brevity I have omitted namespaces and the using statements, which are typically of the form Microsoft.VisualStudio.Text.*. For these to be available, the Visual Studio 2010 SDK must first be downloaded.
I've been using this solution for the past few months without issue.
One limitation I noticed is colours are not 'blended', so a color with less than 100% opacity will not 'fade out' the existing colours in a span - which might be useful to preserve syntax highlighting.
I also have little idea of its efficiency, as it looks like it will repeatedly search a document on each keypress. I have not done the research to see if Visual Studio optimises this somehow. I do notice a slowdown of Visual Studio on large files (> ~1000 lines), but I also use Resharper, so I cannot attribute this to this plugin alone.
As this was coded mostly using guesswork, I welcome any comments or code changes which could clarify or simplify things or improve upon the code's performance.
I guess you could start with Visual Studio Add-in project, it will used EnvDTE, which was considered as Visual Studio Object Model, and please find MSDN document here:
http://msdn.microsoft.com/en-us/vstudio/bb968855
You could control your visual studio behavior, like debugger, code editor and so on by EnvDTE.

get the selected text of the editor window..visual studio extension

hi i'm making a extension for visual studio and the specific thing that i need is get the selected text of the editor windows for further processing. Someone know what interface or service has this?
Previously i need to locate the path of the open solution and for that i ask for a service that implements IVsSolution, so for this other problem I thing that there must be some service that provides me this information.
To clarify "just get the viewhost" in Stacker's answer, here is the full code for how you can get the current editor view, and from there the ITextSelection, from anywhere else in a Visual Studio 2010 VSPackage. In particular, I used this to get the current selection from a menu command callback.
IWpfTextViewHost GetCurrentViewHost()
{
// code to get access to the editor's currently selected text cribbed from
// http://msdn.microsoft.com/en-us/library/dd884850.aspx
IVsTextManager txtMgr = (IVsTextManager)GetService(typeof(SVsTextManager));
IVsTextView vTextView = null;
int mustHaveFocus = 1;
txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
IVsUserData userData = vTextView as IVsUserData;
if (userData == null)
{
return null;
}
else
{
IWpfTextViewHost viewHost;
object holder;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out holder);
viewHost = (IWpfTextViewHost)holder;
return viewHost;
}
}
/// Given an IWpfTextViewHost representing the currently selected editor pane,
/// return the ITextDocument for that view. That's useful for learning things
/// like the filename of the document, its creation date, and so on.
ITextDocument GetTextDocumentForView( IWpfTextViewHost viewHost )
{
ITextDocument document;
viewHost.TextView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out document);
return document;
}
/// Get the current editor selection
ITextSelection GetSelection( IWpfTextViewHost viewHost )
{
return viewHost.TextView.Selection;
}
Here's MSDN's docs for IWpfTextViewHost, ITextDocument, and ITextSelection.
Inside of the OnlayoutChanged, the following code would pop up a message with the code selected:
if (_view.Selection.IsEmpty) return;
else
{
string selectedText = _view.Selection.StreamSelectionSpan.GetText();
MessageBox.Show(selectedText);
}
Anywhere else, just get the viewhost and its _view of typeIWpfTextView

Categories

Resources