added some development tools
[windows-sources.git] / developer / VSSDK / VisualStudioIntegration / Tools / Wizards / Templates / VC / EditorFindAndReplace.inl
blobd55db320b6848d50c4fbcff1b3ee0067f6361698
1 // EditorFindAndReplace.inl
3 #pragma once
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()
14         DWORD dwOptions =
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
27                 FR_Report;        // Report
29         // If the file is "Read Only" then disable the replace options
30         if(IsFileReadOnly())
31         {
32                 dwOptions &= ~(FR_ReplaceAll | FR_Replace);
33         }
35         // If the selection is empty then disable the "Search Selection Only" option
36         if(IsSelectionEmpty())
37         {
38                 dwOptions &= ~FR_Selection;
39         }
41         return dwOptions;
44 template <class Traits_T>
45 STDMETHODIMP EditorDocument<Traits_T>::GetProperty(VSFTPROPID propid, _Out_ VARIANT *pvar)
47         VSL_STDMETHODTRY{
49         VSL_CHECKPOINTER(pvar, E_INVALIDARG);
51         ::VariantClear(pvar);
53         switch(propid)
54         {
55         case VSFTPROPID_DocName: 
56                 CHK(!GetFileName().IsEmpty(), E_UNEXPECTED);
57                 // Return a copy of the file name as the document name
58                 pvar->vt = VT_BSTR;
59                 pvar->bstrVal = ::SysAllocString(GetFileName());
60                 CHKPTR(pvar->bstrVal, E_OUTOFMEMORY);
61                 break;
63         case VSFTPROPID_IsDiskFile: 
64                 pvar->vt = VT_BOOL;
65                 pvar->boolVal = GetFile().IsOnDisk() ? TRUE : FALSE;
66                 break;
68         case VSFTPROPID_InitialPatternAggressive:
69                 // Intentional fall through
70         case VSFTPROPID_InitialPattern: 
71                 pvar->vt = VT_BSTR;
72                 GetInitialPattern(&pvar->bstrVal);
73                 break;
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
80                 break;
81         default:
82                 VSL_SET_STDMETHOD_HRESULT(E_NOTIMPL);
83         }
85         }VSL_STDMETHODCATCH()
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)
94         VSL_STDMETHODTRY{
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);
105         if(lStartIndex < 0)
106         {
107                 return E_INVALIDARG;  // Caller gave us a faulty text span
108         }
110         long lEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
111         if(lEndIndex < 0)       
112         {
113                 return E_INVALIDARG;  // Caller gave us a faulty text span
114         }
116         GetControl().SetSelection(lStartIndex, lEndIndex);
117         
118         }VSL_STDMETHODCATCH()
120         return VSL_GET_STDMETHOD_HRESULT();
123 template <class Traits_T>
124 STDMETHODIMP EditorDocument<Traits_T>::GetCurrentSpan(_Out_ TextSpan* pts)
126         VSL_STDMETHODTRY{
128         VSL_CHECKPOINTER(pts, E_INVALIDARG);
130         CComPtr<ITextSelection> spTextSelection;
131         GetTextSelection(spTextSelection);
133         long iSpanStart = 0;
134         CHKHR(spTextSelection->GetStart(&iSpanStart));
136         long iSpanEnd = 0;
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)
158         VSL_STDMETHODTRY{
160         VSL_CHECKPOINTER(pcLines, E_INVALIDARG);
162         long iLines = GetControl().GetLineCount();
164         *pcLines = iLines;
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)
179         VSL_STDMETHODTRY{
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);
185         if(iStartIndex < 0)
186         {
187                 return E_INVALIDARG; // pts is bad
188         }
190         long iEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
191         if(iEndIndex < 0)
192         {
193                 return E_INVALIDARG; // pts is bad
194         }
196         // Set the selection
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)
217         {
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));
221         }
222         else
223         {
224                 // If the search is backward, then set the end postion at the
225                 // beginning of the new text.
226                 CHKHR(spTextSelection->SetEnd(iSelectionStart));
227         }
229         // Set ptsSpan to contain the replaced text's span info if caller requests for it
230         if(ptsChanged)
231         {
232                 ptsChanged->iStartLine = GetControl().GetLineFromIndex(iSelectionStart);
233                 ptsChanged->iStartIndex = GetControl().GetCharacterPositionFromIndex(iSelectionStart);
234                 ptsChanged->iEndLine = GetControl().GetLineFromIndex(iEndPosition);
235                 ptsChanged->iEndIndex = GetControl().GetCharacterPositionFromIndex(iEndPosition);
236         }
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)
249         
250         VSL_STDMETHODTRY{
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);
257         if(iStartIndex < 0)
258         {
259                 return E_INVALIDARG;  // pts is bad
260         }
262         long iEndIndex = GetControl().GetIndexFromLineAndCharacter(pts->iEndLine, pts->iEndIndex);
263         if(iEndIndex < 0)
264         {
265                 return E_INVALIDARG;  // pts is bad
266         }
268         *pcch = ::abs(iEndIndex - iStartIndex);
270         }VSL_STDMETHODCATCH()
272         return VSL_GET_STDMETHOD_HRESULT();
274                 
275 template <class Traits_T>
276 STDMETHODIMP EditorDocument<Traits_T>::GetLineLength( 
277         /* [in] */ LONG iLine,
278         /* [retval][out] */ _Out_ LONG* piLength)
280         VSL_STDMETHODTRY{
282         VSL_CHECKPOINTER(piLength, E_INVALIDARG);
284         if(iLine < 0)
285         {
286                 return E_INVALIDARG;
287         }
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)
305         VSL_STDMETHODTRY{
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();
321         if( iLine < 0 ||
322                 iLine >= iLineCount ||
323                 iStartIndex < 0 ||
324                 iEndIndex < 0 ||
325                 iStartIndex > iEndIndex)  // An empty span is valid
326         {
327                 return E_INVALIDARG;
328         }
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)
334         {
335                 pLineData->pszText = NULL;
336                 return S_OK;
337         }
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)
344         {
345                 return E_INVALIDARG;
346         }
348         // Now, grab the text
349         Pointer<StdArrayPointerTraits<WCHAR> > szText;
350         GetControl().GetLineText(iLine, szText);
352         if(grfGet & gldeSubset)
353         {
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();
359         }
360         // Else, whole line
361         else
362         {
363                 pLineData->iLength = iLineLength;
364                 pLineData->pszText = szText.Detach();
365         }
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)
390         VSL_STDMETHODTRY{
392         VSL_CHECKPOINTER(piLine, E_INVALIDARG);
393         VSL_CHECKPOINTER(piIndex, E_INVALIDARG);
395         *piLine = 0;
396         *piIndex = 0;
398         GetLineSize(piLine); // Get the number of lines in the editor
399         if(*piLine >= 1)
400         {
401                 // We need to subtract 1 to get the index
402                 (*piLine) -= 1;
403         }
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(
424         long iAnchorLine, 
425         ViewCol iAnchorCol, 
426         long iEndLine, 
427         ViewCol iEndCol)
429         // Convert the given inputs to be the start and end index
430         long lStartIndex = GetControl().GetIndexFromLineAndCharacter(iAnchorLine, iAnchorCol);
431         if( lStartIndex < 0 )
432         {
433                 return E_INVALIDARG;
434         }
436         long lEndIndex = GetControl().GetIndexFromLineAndCharacter(iEndLine, iEndCol);
437         if( lEndIndex < 0 )     
438         {
439                 return E_INVALIDARG;
440         }
442         GetControl().SetSelection(lStartIndex, lEndIndex);
444         return S_OK;
447 /////////////////////////////////////////////////////////////////////////////////
448 //    Helper Functions
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())
458         {
459                 return;
460         }
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. 
478         long iEndOrig;
479         CHKHR(spITextSelection->GetEnd(&iEndOrig));
480         long iEndDup;
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)
485         {
486                 return;
487         }
489         // The selection is all within a single line so retrieve the selection text.
490         CHKHR(spITextSelection->GetText(pbstrPattern));