protected virtual void ExpandSmartTagUnderCaret() { ITextView textView = Controller.TextView; SnapshotPoint?insertionPoint = textView.Caret.Position.Point.GetInsertionPoint(buffer => buffer == textView.TextBuffer); if (!insertionPoint.HasValue) { throw new InvalidOperationException(); } ITextSnapshot snapshot = insertionPoint.Value.Snapshot; SnapshotSpan caretSpan = new SnapshotSpan(insertionPoint.Value, 0); IEnumerable <ISmartTagSession> sessions = Controller.Provider.SmartTagBroker.GetSessions(textView); ISmartTagSession session = sessions.FirstOrDefault(i => i.ApplicableToSpan.GetSpan(snapshot).IntersectsWith(caretSpan) && i.Type == SmartTagType.Factoid); List <ISmartTagSession> source = sessions.Where(i => i.Type == SmartTagType.Ephemeral).ToList(); if (session == null) { session = source.FirstOrDefault(i => i.ApplicableToSpan.GetSpan(snapshot).IntersectsWith(caretSpan)); } if (session == null && source.Count == 1) { session = source[0]; } if (session != null) { session.State = SmartTagState.Expanded; } }
private void AddImportTags(ISmartTagSession session, IList <SmartTagActionSet> smartTagActionSets) { var textBuffer = _textBuffer; var span = session.CreateTrackingSpan(textBuffer); var imports = textBuffer.CurrentSnapshot.GetMissingImports(_serviceProvider, span); if (imports == MissingImportAnalysis.Empty) { return; } SmartTagController controller; session.Properties.TryGetProperty <SmartTagController>(typeof(SmartTagController), out controller); var task = Volatile.Read(ref controller._curTask); var origTask = task; var snapshot = textBuffer.CurrentSnapshot; if (task != null && task.ApplicableToSpan.GetSpan(snapshot) != imports.ApplicableToSpan.GetSpan(snapshot)) { // Previous task is invalid, so abort it and we'll start a // new one. task.Abort(); session.Properties.RemoveProperty(typeof(SmartTagAugmentTask)); task = null; } if (task == null) { task = new SmartTagAugmentTask( _serviceProvider, textBuffer, session.TextView, imports ); if (Interlocked.CompareExchange(ref controller._curTask, task, origTask) != origTask) { // Item has been changed by someone else, so abort // Except we should always be on the UI thread here, so // there should be no races. Debug.Fail("Race in AugmentSmartTagSession"); return; } } session.ApplicableToSpan = imports.ApplicableToSpan; var result = task.GetResultIfComplete(); if (result != null && Interlocked.CompareExchange(ref controller._curTask, null, task) == task) { // Provide results if we were the current task and we are // now complete smartTagActionSets.Add(result); } }
public virtual void DismissSmartTag() { ISmartTagSession session = SmartTagSession; SmartTagSession = null; if (session != null && !session.IsDismissed) { session.Dismiss(); } }
public virtual void TriggerSmartTag(ITrackingPoint triggerPoint, SmartTagType type, SmartTagState state) { DismissSmartTag(); ISmartTagSession session = Provider.SmartTagBroker.CreateSmartTagSession(TextView, type, triggerPoint, state); if (session != null) { session.Dismissed += HandleSmartTagDismissed; SmartTagSession = session; } }
private bool ExpandSmartTagUnderCaret() { var insertionPoint = wpfTextView.Caret.Position.Point.GetInsertionPoint(b => b == wpfTextView.TextBuffer); var snapshot = insertionPoint.Value.Snapshot; var caretSpan = new SnapshotSpan(insertionPoint.Value, 0); ReadOnlyCollection <ISmartTagSession> sessions = smartTagBroker.GetSessions(wpfTextView); ISmartTagSession session = sessions.FirstOrDefault(s => s.ApplicableToSpan.GetSpan(snapshot).IntersectsWith(caretSpan) && s.Type == SmartTagType.Factoid) ?? sessions.FirstOrDefault(s => s.ApplicableToSpan.GetSpan(snapshot).IntersectsWith(caretSpan) && s.Type == SmartTagType.Ephemeral) ?? sessions.FirstOrDefault(s => s.Type == SmartTagType.Ephemeral); // VS will only ignore the caret if there is exactly one ephemeral session, but I'm lazy if (session == null) { return(false); } session.State = SmartTagState.Expanded; return(true); }
#pragma warning disable 0618 // TODO: Switch from smart tags to Light Bulb: http://go.microsoft.com/fwlink/?LinkId=394601 internal static ITrackingSpan CreateTrackingSpan(this ISmartTagSession session, ITextBuffer buffer) { var triggerPoint = session.GetTriggerPoint(buffer); var position = triggerPoint.GetPosition(buffer.CurrentSnapshot); if (position == buffer.CurrentSnapshot.Length) { return(((IIntellisenseSession)session).GetApplicableSpan(buffer)); } var triggerChar = triggerPoint.GetCharacter(buffer.CurrentSnapshot); if (position != 0 && !char.IsLetterOrDigit(triggerChar)) { // end of line, back up one char as we may have an identifier return(buffer.CurrentSnapshot.CreateTrackingSpan(position - 1, 1, SpanTrackingMode.EdgeInclusive)); } return(buffer.CurrentSnapshot.CreateTrackingSpan(position, 1, SpanTrackingMode.EdgeInclusive)); }
public void AugmentSmartTagSession(ISmartTagSession session, IList <SmartTagActionSet> smartTagActionSets) { AddImportTags(session, smartTagActionSets); }
private void AddImportTags(ISmartTagSession session, IList<SmartTagActionSet> smartTagActionSets) { var textBuffer = _textBuffer; var span = session.CreateTrackingSpan(textBuffer); var imports = textBuffer.CurrentSnapshot.GetMissingImports(_serviceProvider, span); if (imports == MissingImportAnalysis.Empty) { return; } SmartTagController controller; session.Properties.TryGetProperty<SmartTagController>(typeof(SmartTagController), out controller); if (controller == null) { return; } var task = Volatile.Read(ref controller._curTask); var origTask = task; var snapshot = textBuffer.CurrentSnapshot; if (task != null && task.ApplicableToSpan.GetSpan(snapshot) != imports.ApplicableToSpan.GetSpan(snapshot)) { // Previous task is invalid, so abort it and we'll start a // new one. task.Abort(); session.Properties.RemoveProperty(typeof(SmartTagAugmentTask)); task = null; } if (task == null) { task = new SmartTagAugmentTask( _serviceProvider, textBuffer, session.TextView, imports ); if (Interlocked.CompareExchange(ref controller._curTask, task, origTask) != origTask) { // Item has been changed by someone else, so abort // Except we should always be on the UI thread here, so // there should be no races. Debug.Fail("Race in AugmentSmartTagSession"); return; } } session.ApplicableToSpan = imports.ApplicableToSpan; var result = task.GetResultIfComplete(); if (result != null && Interlocked.CompareExchange(ref controller._curTask, null, task) == task) { // Provide results if we were the current task and we are // now complete smartTagActionSets.Add(result); } }
public void AugmentSmartTagSession(ISmartTagSession session, IList<SmartTagActionSet> smartTagActionSets) { AddImportTags(session, smartTagActionSets); }
private void AddImportTags(ISmartTagSession session, IList<SmartTagActionSet> smartTagActionSets) { var textBuffer = _textBuffer; var span = session.CreateTrackingSpan(textBuffer); var imports = textBuffer.CurrentSnapshot.GetMissingImports(span); IOleComponentManager compMgr; SmartTagController controller; session.Properties.TryGetProperty<IOleComponentManager>(typeof(SmartTagController), out compMgr); session.Properties.TryGetProperty<SmartTagController>(typeof(SmartTagSource.AbortedAugmentInfo), out controller); if (imports != MissingImportAnalysis.Empty) { session.ApplicableToSpan = imports.ApplicableToSpan; // When doing idle processing we can keep getting kicked out and come back. The whole process // of getting the import smart tags is done lazily through iterators. If we keep trying again // and not getting enough idle time we'll never work away through the full list when it's large // (for example 'sys' in a large distro which is imported and exported everywhere). So as long // as we're working on the same location (our SmartTagController tracks this) then we'll keep working // through the same enumerator so we make progress over time. So we'll read the AbortedAugment // here and continue working, and if we run out of idletime we'll add or update the aborted augment. List<ISmartTagAction> actions; IEnumerator<ExportedMemberInfo> importsEnum; if (controller == null || controller._abortedAugment == null) { actions = new List<ISmartTagAction>(); importsEnum = imports.AvailableImports.GetEnumerator(); } else { // continue processing of the old imports importsEnum = controller._abortedAugment.Imports; actions = controller._abortedAugment.Actions; } bool aborted = false; while (importsEnum.MoveNext()) { var import = importsEnum.Current; if (import.IsDefinedInModule) { int lastDot; if ((lastDot = import.Name.LastIndexOf('.')) == -1) { // simple import actions.Add(new ImportSmartTagAction(import.Name, _textBuffer, session.TextView)); } else { // importing a package or member of a module actions.Add(new ImportSmartTagAction(import.Name.Substring(0, lastDot), import.Name.Substring(lastDot + 1), _textBuffer, session.TextView)); } } if (compMgr != null && compMgr.FContinueIdle() == 0) { // we've run out of time, save our progress... if (controller != null) { controller._sessionIsInvalid = true; controller._abortedAugment = new AbortedAugmentInfo(importsEnum, actions); } aborted = true; break; } } if (!aborted && controller != null) { controller._abortedAugment = null; } if (actions.Count > 0) { smartTagActionSets.Add(new SmartTagActionSet(new ReadOnlyCollection<ISmartTagAction>(actions.ToArray()))); } } }
internal void ShowSmartTag(IOleComponentManager compMgr = null) { if (!_sessionIsInvalid) { // caret / text hasn't changed since we last computed the smart tag, don't bother computing again. return; } ITextSnapshot snapshot = _textView.TextViewModel.DataBuffer.CurrentSnapshot; SnapshotPoint? caretPoint = _textView.Caret.Position.Point.GetPoint(snapshot, PositionAffinity.Successor); if (caretPoint != null && _curSession != null && !_curSession.IsDismissed && _curSession.ApplicableToSpan != null && _curSession.ApplicableToSpan.GetSpan(_textView.TextBuffer.CurrentSnapshot).Contains(caretPoint.Value.Position)) { return; } _sessionIsInvalid = false; // Figure out the point in the buffer where we are triggering. // We need to use the view's data buffer as the source location if (_curSession != null && !_curSession.IsDismissed) { _curSession.Dismiss(); } if (!caretPoint.HasValue) { return; } ITrackingPoint triggerPoint = snapshot.CreateTrackingPoint(caretPoint.Value, PointTrackingMode.Positive); ISmartTagSession newSession = _curSession = _broker.CreateSmartTagSession(_textView, SmartTagType.Factoid, triggerPoint, SmartTagState.Collapsed); newSession.Properties.AddProperty(typeof(SmartTagController), compMgr); newSession.Properties.AddProperty(typeof(SmartTagSource.AbortedAugmentInfo), this); newSession.Start(); }