1 // EditorFindAndReplace.inl
5 /***************************************************************************
6 IVsFindTarget implementation
7 ***************************************************************************/
9 // Called by VSL::IVsFindTargetImpl::GetCapabilities and
10 // VSL::IVsFindTargetImpl::GetSearchImage
11 template <class Traits_T>
12 DWORD EditorDocument<Traits_T>::GetCapabilityOptions()
15 FR_MatchCase | // Match case
16 FR_WholeWord | // Match whole word
17 FR_Hidden | // Hidden text
18 FR_Backwards | // Backwards from insertion point
19 FR_Selection | // Search selection only
20 FR_SubFolders | // Support subfolders
21 FR_KeepOpen | // Keep Open
22 FR_Plain | // Plain (as opposed to reg expression)
23 FR_TargetMask | // All targets (FR_Document, FR_OpenDocuments, FR_Files, FR_Project, FR_Solution)
24 FR_ActionMask | // All actions (FR_MarkAll, FR_Find, FR_FindAll, FR_Replace, FR_ReplaceAll)
25 FR_FromStart | // Search from beginning
26 FR_OneMatchPerLine | // One match per line
29 // If the file is "Read Only" then disable the replace options
32 dwOptions &= ~(FR_ReplaceAll | FR_Replace);
35 // If the selection is empty then disable the "Search Selection Only" option
36 if(IsSelectionEmpty())
38 dwOptions &= ~FR_Selection;
44 template <class Traits_T>
45 STDMETHODIMP EditorDocument<Traits_T>::GetProperty(VSFTPROPID propid, _Out_ VARIANT *pvar)
49 VSL_CHECKPOINTER(pvar, E_INVALIDARG);
55 case VSFTPROPID_DocName:
56 CHK(!GetFileName().IsEmpty(), E_UNEXPECTED);
57 // Return a copy of the file name as the document name
59 pvar->bstrVal = ::SysAllocString(GetFileName());
60 CHKPTR(pvar->bstrVal, E_OUTOFMEMORY);
63 case VSFTPROPID_IsDiskFile:
65 pvar->boolVal = GetFile().IsOnDisk() ? TRUE : FALSE;
68 case VSFTPROPID_InitialPatternAggressive:
69 // Intentional fall through
70 case VSFTPROPID_InitialPattern:
72 GetInitialPattern(&pvar->bstrVal);
75 case VSFTPROPID_WindowFrame:
76 pvar->vt = VT_UNKNOWN;
77 // Query the same site provided to the SetSite method of this instance
78 CHKHR(GetVsSiteCache().QueryService(SID_SVsWindowFrame, &pvar->punkVal));
79 CHKPTR(pvar->punkVal, E_NOINTERFACE); // paranoid
82 VSL_SET_STDMETHOD_HRESULT(E_NOTIMPL);
87 return VSL_GET_STDMETHOD_HRESULT();
90 // Callers call into this to tell us to highlight a span in the document
91 template <class Traits_T>
92 STDMETHODIMP EditorDocument<Traits_T>::NavigateTo(const TextSpan* pts)
96 VSL_CHECKPOINTER(pts, E_INVALIDARG);
98 // Make sure the window is visible
99 CComPtr<IVsWindowFrame> spFrame;
100 CHKHR(GetVsSiteCache().QueryService(SID_SVsWindowFrame, &spFrame));
101 CHKHR(spFrame->Show());
103 // Now, tell the editor control to select the span given
104 long lStartIndex = GetControl().GetIndexFromLineAndCharacter(pts->iStartLine, pts->iStartIndex);
107 return E_INVALIDARG; // Caller gave us a faulty text span
110 long lEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
113 return E_INVALIDARG; // Caller gave us a faulty text span
116 GetControl().SetSelection(lStartIndex, lEndIndex);
118 }VSL_STDMETHODCATCH()
120 return VSL_GET_STDMETHOD_HRESULT();
123 template <class Traits_T>
124 STDMETHODIMP EditorDocument<Traits_T>::GetCurrentSpan(_Out_ TextSpan* pts)
128 VSL_CHECKPOINTER(pts, E_INVALIDARG);
130 CComPtr<ITextSelection> spTextSelection;
131 GetTextSelection(spTextSelection);
134 CHKHR(spTextSelection->GetStart(&iSpanStart));
137 CHKHR(spTextSelection->GetEnd(&iSpanEnd));
139 pts->iStartLine = GetControl().GetLineFromIndex(iSpanStart);
140 pts->iStartIndex = GetControl().GetCharacterPositionFromIndex(iSpanStart);
141 pts->iEndLine = GetControl().GetLineFromIndex(iSpanEnd);
142 pts->iEndIndex = GetControl().GetCharacterPositionFromIndex(iSpanEnd);
144 }VSL_STDMETHODCATCH()
146 return VSL_GET_STDMETHOD_HRESULT();
149 /***************************************************************************
150 IVsTextImage implementation
151 ***************************************************************************/
153 // Returns the number of lines in the editor
154 template <class Traits_T>
155 STDMETHODIMP EditorDocument<Traits_T>::GetLineSize(
156 /* [retval][out] */ _Out_ LONG* pcLines)
160 VSL_CHECKPOINTER(pcLines, E_INVALIDARG);
162 long iLines = GetControl().GetLineCount();
166 }VSL_STDMETHODCATCH()
168 return VSL_GET_STDMETHOD_HRESULT();
171 template <class Traits_T>
172 STDMETHODIMP EditorDocument<Traits_T>::Replace(
173 /* [in] */ DWORD dwFlags,
174 /* [in] */ const TextSpan* pts,
175 /* [in] */ LONG /*cch*/,
176 /* [size_is][in] */ LPCOLESTR pchText,
177 /* [retval][out] */ _Out_ TextSpan* ptsChanged)
181 VSL_CHECKPOINTER(pts, E_INVALIDARG);
183 // pts contains the span of the text to replace. Set the selection to be pts.
184 long iStartIndex = GetControl().GetIndexFromLineAndCharacter(pts->iStartLine, pts->iStartIndex);
187 return E_INVALIDARG; // pts is bad
190 long iEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
193 return E_INVALIDARG; // pts is bad
197 GetControl().SetSelection(iStartIndex, iEndIndex);
199 CComPtr<ITextSelection> spTextSelection;
200 GetTextSelection(spTextSelection);
202 // Store the starting position of this selection
203 long iSelectionStart = 0;
204 CHKHR(spTextSelection->GetStart(&iSelectionStart));
206 // Call the function to replace the currently selected text
207 // with the given replacement string
208 CComBSTR bstrReplace = pchText; // Replacement text
210 // Do the actual replace
211 CHKHR(spTextSelection->SetText(bstrReplace));
213 long iEndPosition = 0;
214 CHKHR(spTextSelection->GetEnd(&iEndPosition));
216 if ((dwFlags & FR_Backwards) == 0)
218 // In case of forward search place the insertion point at the end of the new text,
219 // so it will be skipped during the next call to Find.
220 CHKHR(spTextSelection->SetStart(iEndPosition));
224 // If the search is backward, then set the end postion at the
225 // beginning of the new text.
226 CHKHR(spTextSelection->SetEnd(iSelectionStart));
229 // Set ptsSpan to contain the replaced text's span info if caller requests for it
232 ptsChanged->iStartLine = GetControl().GetLineFromIndex(iSelectionStart);
233 ptsChanged->iStartIndex = GetControl().GetCharacterPositionFromIndex(iSelectionStart);
234 ptsChanged->iEndLine = GetControl().GetLineFromIndex(iEndPosition);
235 ptsChanged->iEndIndex = GetControl().GetCharacterPositionFromIndex(iEndPosition);
238 }VSL_STDMETHODCATCH()
240 return VSL_GET_STDMETHOD_HRESULT();
243 // Note, line endings are included in the length of a span
244 template <class Traits_T>
245 STDMETHODIMP EditorDocument<Traits_T>::GetSpanLength(
246 /* [in] */ const TextSpan* pts,
247 /* [retval][out] */ _Out_ LONG* pcch)
252 VSL_CHECKPOINTER(pts, E_INVALIDARG);
253 VSL_CHECKPOINTER(pcch, E_INVALIDARG);
255 // Need to convert the starting and end points of the span into their index equivalent
256 long iStartIndex = GetControl().GetIndexFromLineAndCharacter(pts->iStartLine, pts->iStartIndex);
259 return E_INVALIDARG; // pts is bad
262 long iEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
265 return E_INVALIDARG; // pts is bad
268 *pcch = ::abs(iEndIndex - iStartIndex);
270 }VSL_STDMETHODCATCH()
272 return VSL_GET_STDMETHOD_HRESULT();
275 template <class Traits_T>
276 STDMETHODIMP EditorDocument<Traits_T>::GetLineLength(
277 /* [in] */ LONG iLine,
278 /* [retval][out] */ _Out_ LONG* piLength)
282 VSL_CHECKPOINTER(piLength, E_INVALIDARG);
289 // Convert the line number into an index equivalent
290 *piLength = GetControl().GetLineLength(iLine);
292 }VSL_STDMETHODCATCH()
294 return VSL_GET_STDMETHOD_HRESULT();
297 template <class Traits_T>
298 STDMETHODIMP EditorDocument<Traits_T>::GetLine(
299 /* [in] */ DWORD grfGet,
300 /* [in] */ LONG iLine,
301 /* [in] */ LONG iStartIndex,
302 /* [in] */ LONG iEndIndex,
303 /* [retval][out] */ _Out_ LINEDATAEX* pLineData)
307 VSL_CHECKPOINTER(pLineData, E_INVALIDARG);
309 // Initialize pLineData
310 pLineData->iLength = 0;
311 pLineData->pszText = NULL;
312 pLineData->iEolType = eolCR;
313 pLineData->pAttributes = 0;
314 pLineData->dwFlags = static_cast<USHORT>(ldfDefault);
315 pLineData->dwReserved = 0;
316 pLineData->pAtomicTextChain = NULL;
318 // First, make sure all of the inputs make sense
319 long iLineCount = GetControl().GetLineCount();
322 iLine >= iLineCount ||
325 iStartIndex > iEndIndex) // An empty span is valid
330 // Length of the line is the span between the start and end index
331 long iLineLength = GetControl().GetLineLength(iLine);
332 // Check if the line is empty and the caller asks for an empty span.
333 if (0 == iLineLength && 0 == iStartIndex && 0 == iEndIndex)
335 pLineData->pszText = NULL;
339 // Get the length of the span.
340 long iLineSpanLength = iEndIndex - iStartIndex +1;
342 // If the span length determined by the start and end index is greater than the length of the line, this is an error
343 if(iLineSpanLength > iLineLength)
348 // Now, grab the text
349 Pointer<StdArrayPointerTraits<WCHAR> > szText;
350 GetControl().GetLineText(iLine, szText);
352 if(grfGet & gldeSubset)
354 pLineData->iLength = iLineSpanLength;
355 Pointer<StdArrayPointerTraits<WCHAR> > szSubText = new WCHAR[iLineSpanLength+1]; // Plus 1 for NULL
356 // Now, copy the substring
357 CHK(0 == ::wcsncpy_s(szSubText, iLineSpanLength+1, szText+iStartIndex, iLineSpanLength), E_FAIL);
358 pLineData->pszText = szSubText.Detach();
363 pLineData->iLength = iLineLength;
364 pLineData->pszText = szText.Detach();
367 }VSL_STDMETHODCATCH()
369 return VSL_GET_STDMETHOD_HRESULT();
372 /***************************************************************************
373 IVsTextBuffer implementation
375 This is just provided so that the find in files scenario will work
376 properly. It isn't necesary to implement most of the methods for this
377 scenario to work correctly.
378 ***************************************************************************/
380 template <class Traits_T>
381 STDMETHODIMP EditorDocument<Traits_T>::GetLengthOfLine(long iLine, _Out_ long* piLength)
383 // defer to IVsTextImage::GetLineLength
384 return GetLineLength(iLine, piLength);
387 template <class Traits_T>
388 STDMETHODIMP EditorDocument<Traits_T>::GetLastLineIndex(_Out_ long* piLine, _Out_ long* piIndex)
392 VSL_CHECKPOINTER(piLine, E_INVALIDARG);
393 VSL_CHECKPOINTER(piIndex, E_INVALIDARG);
398 GetLineSize(piLine); // Get the number of lines in the editor
401 // We need to subtract 1 to get the index
405 // Now, get the line length of the last line
406 long cLineLength = GetControl().GetLineLength(*piLine);
407 *piIndex = (cLineLength >= 1 ? cLineLength - 1 : cLineLength);
409 }VSL_STDMETHODCATCH()
411 return VSL_GET_STDMETHOD_HRESULT();
414 /***************************************************************************
415 IVsTextView implementation
417 This is just provided so that the find in files scenario will work
418 properly. It isn't necesary to implement most of the methods for this
419 scenario to work correctly.
420 ***************************************************************************/
422 template <class Traits_T>
423 STDMETHODIMP EditorDocument<Traits_T>::SetSelection(
429 // Convert the given inputs to be the start and end index
430 long lStartIndex = GetControl().GetIndexFromLineAndCharacter(iAnchorLine, iAnchorCol);
431 if( lStartIndex < 0 )
436 long lEndIndex = GetControl().GetIndexFromLineAndCharacter(iEndLine, iEndCol);
442 GetControl().SetSelection(lStartIndex, lEndIndex);
447 /////////////////////////////////////////////////////////////////////////////////
449 /////////////////////////////////////////////////////////////////////////////////
451 template <class Traits_T>
452 void EditorDocument<Traits_T>::GetInitialPattern(_Deref_out_z_ BSTR* pbstrPattern)
454 *pbstrPattern = NULL;
456 // First check if the selection is empty.
457 if(IsSelectionEmpty())
462 // Now check if the selection is multiline by:
463 // - Getting and then duplicating the current text range.
464 // - Advancing the start of the duplicate by one line
465 // - Checking if the duplicate range is still within
466 // the original range.
467 // If the check is true then the selection is multiline.
468 CComPtr<ITextSelection> spITextSelection;
469 GetTextSelection(spITextSelection);
471 // Duplicate the text selection
472 CComPtr<ITextRange> spDuplicate;
473 CHKHR(spITextSelection->GetDuplicate(&spDuplicate));
474 // Advance the start of the duplicate by one line
475 CHKHR(spDuplicate->MoveStart(tomLine, 1, NULL));
477 // Get the ends of each range.
479 CHKHR(spITextSelection->GetEnd(&iEndOrig));
481 CHKHR(spDuplicate->GetEnd(&iEndDup));
483 // If the ends are still the same are still the same then the selection is multiline.
484 if(iEndOrig == iEndDup)
489 // The selection is all within a single line so retrieve the selection text.
490 CHKHR(spITextSelection->GetText(pbstrPattern));