blob: 111b163c4238efba31affd66f2e67066ac7d1daf [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001#include "stdafx.h"
2#include <comdef.h> // For _bstr_t
3#include "VisVim.h"
4#include "Commands.h"
5#include "OleAut.h"
6
7#ifdef _DEBUG
8#define new DEBUG_NEW
9#undef THIS_FILE
10static char THIS_FILE[] = __FILE__;
11
12#endif
13
14
15// Change directory before opening file?
16#define CD_SOURCE 0 // Cd to source path
17#define CD_SOURCE_PARENT 1 // Cd to parent directory of source path
18#define CD_NONE 2 // No cd
19
20
21static BOOL g_bEnableVim = TRUE; // Vim enabled
22static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously
Bram Moolenaar99133032009-04-22 11:08:26 +000023static BOOL g_bNewTabs = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +000024static int g_ChangeDir = CD_NONE; // CD after file open?
25
Bram Moolenaar99133032009-04-22 11:08:26 +000026static void VimSetEnableState(BOOL bEnableState);
27static BOOL VimOpenFile(BSTR& FileName, long LineNr);
28static DISPID VimGetDispatchId(COleAutomationControl& VimOle, char* Method);
29static void VimErrDiag(COleAutomationControl& VimOle);
30static void VimChangeDir(COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName);
31static void DebugMsg(char* Msg, char* Arg = NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +000032
33
34/////////////////////////////////////////////////////////////////////////////
35// CCommands
36
Bram Moolenaar99133032009-04-22 11:08:26 +000037CCommands::CCommands()
Bram Moolenaar071d4272004-06-13 20:20:40 +000038{
39 // m_pApplication == NULL; M$ Code generation bug!!!
40 m_pApplication = NULL;
41 m_pApplicationEventsObj = NULL;
42 m_pDebuggerEventsObj = NULL;
43}
44
Bram Moolenaar99133032009-04-22 11:08:26 +000045CCommands::~CCommands()
Bram Moolenaar071d4272004-06-13 20:20:40 +000046{
Bram Moolenaar99133032009-04-22 11:08:26 +000047 ASSERT(m_pApplication != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +000048 if (m_pApplication)
49 {
Bram Moolenaar99133032009-04-22 11:08:26 +000050 m_pApplication->Release();
Bram Moolenaar071d4272004-06-13 20:20:40 +000051 m_pApplication = NULL;
52 }
53}
54
Bram Moolenaar99133032009-04-22 11:08:26 +000055void CCommands::SetApplicationObject(IApplication * pApplication)
Bram Moolenaar071d4272004-06-13 20:20:40 +000056{
57 // This function assumes pApplication has already been AddRef'd
Bram Moolenaare5901192007-05-10 18:46:18 +000058 // for us, which CDSAddIn did in it's QueryInterface call
Bram Moolenaar071d4272004-06-13 20:20:40 +000059 // just before it called us.
60 m_pApplication = pApplication;
61 if (! m_pApplication)
62 return;
63
64 // Create Application event handlers
Bram Moolenaar99133032009-04-22 11:08:26 +000065 XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
Bram Moolenaar071d4272004-06-13 20:20:40 +000066 if (! m_pApplicationEventsObj)
67 {
Bram Moolenaar99133032009-04-22 11:08:26 +000068 ReportInternalError("XApplicationEventsObj::CreateInstance");
Bram Moolenaar071d4272004-06-13 20:20:40 +000069 return;
70 }
Bram Moolenaar99133032009-04-22 11:08:26 +000071 m_pApplicationEventsObj->AddRef();
72 m_pApplicationEventsObj->Connect(m_pApplication);
Bram Moolenaar071d4272004-06-13 20:20:40 +000073 m_pApplicationEventsObj->m_pCommands = this;
74
75#ifdef NEVER
76 // Create Debugger event handler
77 CComPtr < IDispatch > pDebugger;
Bram Moolenaar99133032009-04-22 11:08:26 +000078 if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger))
Bram Moolenaar071d4272004-06-13 20:20:40 +000079 && pDebugger != NULL)
80 {
Bram Moolenaar99133032009-04-22 11:08:26 +000081 XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
82 m_pDebuggerEventsObj->AddRef();
83 m_pDebuggerEventsObj->Connect(pDebugger);
Bram Moolenaar071d4272004-06-13 20:20:40 +000084 m_pDebuggerEventsObj->m_pCommands = this;
85 }
86#endif
87
88 // Get settings from registry HKEY_CURRENT_USER\Software\Vim\VisVim
Bram Moolenaar99133032009-04-22 11:08:26 +000089 HKEY hAppKey = GetAppKey("Vim");
Bram Moolenaar071d4272004-06-13 20:20:40 +000090 if (hAppKey)
91 {
Bram Moolenaar99133032009-04-22 11:08:26 +000092 HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 if (hSectionKey)
94 {
Bram Moolenaar99133032009-04-22 11:08:26 +000095 g_bEnableVim = GetRegistryInt(hSectionKey, "EnableVim",
Bram Moolenaar071d4272004-06-13 20:20:40 +000096 g_bEnableVim);
Bram Moolenaar99133032009-04-22 11:08:26 +000097 g_bDevStudioEditor = GetRegistryInt(hSectionKey,
98 "DevStudioEditor", g_bDevStudioEditor);
99 g_bNewTabs = GetRegistryInt(hSectionKey, "NewTabs",
100 g_bNewTabs);
101 g_ChangeDir = GetRegistryInt(hSectionKey, "ChangeDir",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102 g_ChangeDir);
Bram Moolenaar99133032009-04-22 11:08:26 +0000103 RegCloseKey(hSectionKey);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104 }
Bram Moolenaar99133032009-04-22 11:08:26 +0000105 RegCloseKey(hAppKey);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106 }
107}
108
Bram Moolenaar99133032009-04-22 11:08:26 +0000109void CCommands::UnadviseFromEvents()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110{
Bram Moolenaar99133032009-04-22 11:08:26 +0000111 ASSERT(m_pApplicationEventsObj != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112 if (m_pApplicationEventsObj)
113 {
Bram Moolenaar99133032009-04-22 11:08:26 +0000114 m_pApplicationEventsObj->Disconnect(m_pApplication);
115 m_pApplicationEventsObj->Release();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 m_pApplicationEventsObj = NULL;
117 }
118
119#ifdef NEVER
120 if (m_pDebuggerEventsObj)
121 {
122 // Since we were able to connect to the Debugger events, we
123 // should be able to access the Debugger object again to
124 // unadvise from its events (thus the VERIFY_OK below--see
125 // stdafx.h).
126 CComPtr < IDispatch > pDebugger;
Bram Moolenaar99133032009-04-22 11:08:26 +0000127 VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
128 ASSERT(pDebugger != NULL);
129 m_pDebuggerEventsObj->Disconnect(pDebugger);
130 m_pDebuggerEventsObj->Release();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131 m_pDebuggerEventsObj = NULL;
132 }
133#endif
134}
135
136
137/////////////////////////////////////////////////////////////////////////////
138// Event handlers
139
140// Application events
141
Bram Moolenaar99133032009-04-22 11:08:26 +0000142HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143{
Bram Moolenaar99133032009-04-22 11:08:26 +0000144 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145 return S_OK;
146}
147
Bram Moolenaar99133032009-04-22 11:08:26 +0000148HRESULT CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149{
Bram Moolenaar99133032009-04-22 11:08:26 +0000150 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151 return S_OK;
152}
153
Bram Moolenaar99133032009-04-22 11:08:26 +0000154HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155{
Bram Moolenaar99133032009-04-22 11:08:26 +0000156 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 return S_OK;
158}
159
160// The open document event handle is the place where the real interface work
161// is done.
162// Vim gets called from here.
163//
Bram Moolenaar99133032009-04-22 11:08:26 +0000164HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch * theDocument)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165{
Bram Moolenaar99133032009-04-22 11:08:26 +0000166 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167
168 if (! g_bEnableVim)
169 // Vim not enabled or empty command line entered
170 return S_OK;
171
172 // First get the current file name and line number
173
174 // Get the document object
Bram Moolenaar99133032009-04-22 11:08:26 +0000175 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176 if (! pDoc)
177 return S_OK;
178
179 BSTR FileName;
180 long LineNr = -1;
181
182 // Get the document name
Bram Moolenaar99133032009-04-22 11:08:26 +0000183 if (FAILED(pDoc->get_FullName(&FileName)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184 return S_OK;
185
186 LPDISPATCH pDispSel;
187
188 // Get a selection object dispatch pointer
Bram Moolenaar99133032009-04-22 11:08:26 +0000189 if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190 {
191 // Get the selection object
Bram Moolenaar99133032009-04-22 11:08:26 +0000192 CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000193
194 if (pSel)
195 // Get the selection line number
Bram Moolenaar99133032009-04-22 11:08:26 +0000196 pSel->get_CurrentLine(&LineNr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197
Bram Moolenaar99133032009-04-22 11:08:26 +0000198 pDispSel->Release();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199 }
200
201 // Open the file in Vim and position to the current line
Bram Moolenaar99133032009-04-22 11:08:26 +0000202 if (VimOpenFile(FileName, LineNr))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203 {
204 if (! g_bDevStudioEditor)
205 {
206 // Close the document in developer studio
207 CComVariant vSaveChanges = dsSaveChangesPrompt;
208 DsSaveStatus Saved;
209
Bram Moolenaar99133032009-04-22 11:08:26 +0000210 pDoc->Close(vSaveChanges, &Saved);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211 }
212 }
213
214 // We're done here
Bram Moolenaar99133032009-04-22 11:08:26 +0000215 SysFreeString(FileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 return S_OK;
217}
218
Bram Moolenaar99133032009-04-22 11:08:26 +0000219HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch * theDocument)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220{
Bram Moolenaar99133032009-04-22 11:08:26 +0000221 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222 return S_OK;
223}
224
Bram Moolenaar99133032009-04-22 11:08:26 +0000225HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch * theDocument)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226{
Bram Moolenaar99133032009-04-22 11:08:26 +0000227 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 return S_OK;
229}
230
Bram Moolenaar99133032009-04-22 11:08:26 +0000231HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch * theDocument)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232{
Bram Moolenaar99133032009-04-22 11:08:26 +0000233 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234
235 if (! g_bEnableVim)
236 // Vim not enabled or empty command line entered
237 return S_OK;
238
239 // First get the current file name and line number
240
Bram Moolenaar99133032009-04-22 11:08:26 +0000241 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000242 if (! pDoc)
243 return S_OK;
244
245 BSTR FileName;
246 HRESULT hr;
247
Bram Moolenaar99133032009-04-22 11:08:26 +0000248 hr = pDoc->get_FullName(&FileName);
249 if (FAILED(hr))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250 return S_OK;
251
252 // Open the file in Vim and position to the current line
Bram Moolenaar99133032009-04-22 11:08:26 +0000253 if (VimOpenFile(FileName, 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 {
255 if (! g_bDevStudioEditor)
256 {
257 // Close the document in developer studio
258 CComVariant vSaveChanges = dsSaveChangesPrompt;
259 DsSaveStatus Saved;
260
Bram Moolenaar99133032009-04-22 11:08:26 +0000261 pDoc->Close(vSaveChanges, &Saved);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 }
263 }
264
Bram Moolenaar99133032009-04-22 11:08:26 +0000265 SysFreeString(FileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000266 return S_OK;
267}
268
Bram Moolenaar99133032009-04-22 11:08:26 +0000269HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch * theWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270{
Bram Moolenaar99133032009-04-22 11:08:26 +0000271 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 return S_OK;
273}
274
Bram Moolenaar99133032009-04-22 11:08:26 +0000275HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch * theWindow)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276{
Bram Moolenaar99133032009-04-22 11:08:26 +0000277 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278 return S_OK;
279}
280
Bram Moolenaar99133032009-04-22 11:08:26 +0000281HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282{
Bram Moolenaar99133032009-04-22 11:08:26 +0000283 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284 return S_OK;
285}
286
Bram Moolenaar99133032009-04-22 11:08:26 +0000287HRESULT CCommands::XApplicationEvents::WorkspaceClose()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288{
Bram Moolenaar99133032009-04-22 11:08:26 +0000289 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000290 return S_OK;
291}
292
Bram Moolenaar99133032009-04-22 11:08:26 +0000293HRESULT CCommands::XApplicationEvents::NewWorkspace()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294{
Bram Moolenaar99133032009-04-22 11:08:26 +0000295 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 return S_OK;
297}
298
299// Debugger event
300
Bram Moolenaar99133032009-04-22 11:08:26 +0000301HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch * pBreakpoint)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302{
Bram Moolenaar99133032009-04-22 11:08:26 +0000303 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000304 return S_OK;
305}
306
307
308/////////////////////////////////////////////////////////////////////////////
309// VisVim dialog
310
311class CMainDialog : public CDialog
312{
313 public:
Bram Moolenaar99133032009-04-22 11:08:26 +0000314 CMainDialog(CWnd * pParent = NULL); // Standard constructor
Bram Moolenaar071d4272004-06-13 20:20:40 +0000315
316 //{{AFX_DATA(CMainDialog)
317 enum { IDD = IDD_ADDINMAIN };
318 int m_ChangeDir;
319 BOOL m_bDevStudioEditor;
Bram Moolenaar99133032009-04-22 11:08:26 +0000320 BOOL m_bNewTabs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321 //}}AFX_DATA
322
323 //{{AFX_VIRTUAL(CMainDialog)
324 protected:
Bram Moolenaar99133032009-04-22 11:08:26 +0000325 virtual void DoDataExchange(CDataExchange * pDX); // DDX/DDV support
Bram Moolenaar071d4272004-06-13 20:20:40 +0000326 //}}AFX_VIRTUAL
327
328 protected:
329 //{{AFX_MSG(CMainDialog)
330 afx_msg void OnEnable();
331 afx_msg void OnDisable();
332 //}}AFX_MSG
Bram Moolenaar99133032009-04-22 11:08:26 +0000333 DECLARE_MESSAGE_MAP()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334};
335
Bram Moolenaar99133032009-04-22 11:08:26 +0000336CMainDialog::CMainDialog(CWnd * pParent /* =NULL */ )
337 : CDialog(CMainDialog::IDD, pParent)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338{
339 //{{AFX_DATA_INIT(CMainDialog)
340 m_ChangeDir = -1;
341 m_bDevStudioEditor = FALSE;
Bram Moolenaar99133032009-04-22 11:08:26 +0000342 m_bNewTabs = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 //}}AFX_DATA_INIT
344}
345
Bram Moolenaar99133032009-04-22 11:08:26 +0000346void CMainDialog::DoDataExchange(CDataExchange * pDX)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347{
Bram Moolenaar99133032009-04-22 11:08:26 +0000348 CDialog::DoDataExchange(pDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 //{{AFX_DATA_MAP(CMainDialog)
350 DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
Bram Moolenaar99133032009-04-22 11:08:26 +0000351 DDX_Check(pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
352 DDX_Check(pDX, IDC_NEW_TABS, m_bNewTabs);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 //}}AFX_DATA_MAP
354}
355
Bram Moolenaar99133032009-04-22 11:08:26 +0000356BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 //{{AFX_MSG_MAP(CMainDialog)
358 //}}AFX_MSG_MAP
Bram Moolenaar99133032009-04-22 11:08:26 +0000359END_MESSAGE_MAP()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000360
361
362/////////////////////////////////////////////////////////////////////////////
363// CCommands methods
364
Bram Moolenaar99133032009-04-22 11:08:26 +0000365STDMETHODIMP CCommands::VisVimDialog()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000366{
Bram Moolenaar99133032009-04-22 11:08:26 +0000367 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368
369 // Use m_pApplication to access the Developer Studio Application
370 // object,
371 // and VERIFY_OK to see error strings in DEBUG builds of your add-in
372 // (see stdafx.h)
373
Bram Moolenaar99133032009-04-22 11:08:26 +0000374 VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375
376 CMainDialog Dlg;
377
378 Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
Bram Moolenaar99133032009-04-22 11:08:26 +0000379 Dlg.m_bNewTabs = g_bNewTabs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 Dlg.m_ChangeDir = g_ChangeDir;
Bram Moolenaar99133032009-04-22 11:08:26 +0000381 if (Dlg.DoModal() == IDOK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 {
383 g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
Bram Moolenaar99133032009-04-22 11:08:26 +0000384 g_bNewTabs = Dlg.m_bNewTabs;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 g_ChangeDir = Dlg.m_ChangeDir;
386
387 // Save settings to registry HKEY_CURRENT_USER\Software\Vim\VisVim
Bram Moolenaar99133032009-04-22 11:08:26 +0000388 HKEY hAppKey = GetAppKey("Vim");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 if (hAppKey)
390 {
Bram Moolenaar99133032009-04-22 11:08:26 +0000391 HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 if (hSectionKey)
393 {
Bram Moolenaar99133032009-04-22 11:08:26 +0000394 WriteRegistryInt(hSectionKey, "DevStudioEditor",
Bram Moolenaar071d4272004-06-13 20:20:40 +0000395 g_bDevStudioEditor);
Bram Moolenaar99133032009-04-22 11:08:26 +0000396 WriteRegistryInt(hSectionKey, "NewTabs",
397 g_bNewTabs);
398 WriteRegistryInt(hSectionKey, "ChangeDir", g_ChangeDir);
399 RegCloseKey(hSectionKey);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 }
Bram Moolenaar99133032009-04-22 11:08:26 +0000401 RegCloseKey(hAppKey);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402 }
403 }
404
Bram Moolenaar99133032009-04-22 11:08:26 +0000405 VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 return S_OK;
407}
408
Bram Moolenaar99133032009-04-22 11:08:26 +0000409STDMETHODIMP CCommands::VisVimEnable()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410{
Bram Moolenaar99133032009-04-22 11:08:26 +0000411 AFX_MANAGE_STATE(AfxGetStaticModuleState());
412 VimSetEnableState(true);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413 return S_OK;
414}
415
Bram Moolenaar99133032009-04-22 11:08:26 +0000416STDMETHODIMP CCommands::VisVimDisable()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417{
Bram Moolenaar99133032009-04-22 11:08:26 +0000418 AFX_MANAGE_STATE(AfxGetStaticModuleState());
419 VimSetEnableState(false);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 return S_OK;
421}
422
Bram Moolenaar99133032009-04-22 11:08:26 +0000423STDMETHODIMP CCommands::VisVimToggle()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424{
Bram Moolenaar99133032009-04-22 11:08:26 +0000425 AFX_MANAGE_STATE(AfxGetStaticModuleState());
426 VimSetEnableState(! g_bEnableVim);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 return S_OK;
428}
429
Bram Moolenaar99133032009-04-22 11:08:26 +0000430STDMETHODIMP CCommands::VisVimLoad()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431{
Bram Moolenaar99133032009-04-22 11:08:26 +0000432 AFX_MANAGE_STATE(AfxGetStaticModuleState());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433
434 // Use m_pApplication to access the Developer Studio Application object,
435 // and VERIFY_OK to see error strings in DEBUG builds of your add-in
436 // (see stdafx.h)
437
438 CComBSTR bStr;
439 // Define dispatch pointers for document and selection objects
440 CComPtr < IDispatch > pDispDoc, pDispSel;
441
442 // Get a document object dispatch pointer
Bram Moolenaar99133032009-04-22 11:08:26 +0000443 VERIFY_OK(m_pApplication->get_ActiveDocument(&pDispDoc));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000444 if (! pDispDoc)
445 return S_OK;
446
447 BSTR FileName;
448 long LineNr = -1;
449
450 // Get the document object
Bram Moolenaar99133032009-04-22 11:08:26 +0000451 CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(pDispDoc);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452
453 if (! pDoc)
454 return S_OK;
455
456 // Get the document name
Bram Moolenaar99133032009-04-22 11:08:26 +0000457 if (FAILED(pDoc->get_FullName(&FileName)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 return S_OK;
459
460 // Get a selection object dispatch pointer
Bram Moolenaar99133032009-04-22 11:08:26 +0000461 if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 {
463 // Get the selection object
Bram Moolenaar99133032009-04-22 11:08:26 +0000464 CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465
466 if (pSel)
467 // Get the selection line number
Bram Moolenaar99133032009-04-22 11:08:26 +0000468 pSel->get_CurrentLine(&LineNr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000469 }
470
471 // Open the file in Vim
Bram Moolenaar99133032009-04-22 11:08:26 +0000472 VimOpenFile(FileName, LineNr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000473
Bram Moolenaar99133032009-04-22 11:08:26 +0000474 SysFreeString(FileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475 return S_OK;
476}
477
478
479//
480// Here we do the actual processing and communication with Vim
481//
482
483// Set the enable state and save to registry
484//
Bram Moolenaar99133032009-04-22 11:08:26 +0000485static void VimSetEnableState(BOOL bEnableState)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486{
487 g_bEnableVim = bEnableState;
Bram Moolenaar99133032009-04-22 11:08:26 +0000488 HKEY hAppKey = GetAppKey("Vim");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000489 if (hAppKey)
490 {
Bram Moolenaar99133032009-04-22 11:08:26 +0000491 HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 if (hSectionKey)
Bram Moolenaar99133032009-04-22 11:08:26 +0000493 WriteRegistryInt(hSectionKey, "EnableVim", g_bEnableVim);
494 RegCloseKey(hAppKey);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 }
496}
497
498// Open the file 'FileName' in Vim and goto line 'LineNr'
499// 'FileName' is expected to contain an absolute DOS path including the drive
500// letter.
501// 'LineNr' must contain a valid line number or 0, e. g. for a new file
502//
Bram Moolenaar99133032009-04-22 11:08:26 +0000503static BOOL VimOpenFile(BSTR& FileName, long LineNr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504{
505
506 // OLE automation object for com. with Vim
Bram Moolenaare5901192007-05-10 18:46:18 +0000507 // When the object goes out of scope, it's destructor destroys the OLE
508 // connection;
509 // This is important to avoid blocking the object
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 // (in this memory corruption would be likely when terminating Vim
511 // while still running DevStudio).
512 // So keep this object local!
513 COleAutomationControl VimOle;
514
515 // :cd D:/Src2/VisVim/
516 //
517 // Get a dispatch id for the SendKeys method of Vim;
518 // enables connection to Vim if necessary
519 DISPID DispatchId;
Bram Moolenaar99133032009-04-22 11:08:26 +0000520 DispatchId = VimGetDispatchId(VimOle, "SendKeys");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 if (! DispatchId)
522 // OLE error, can't obtain dispatch id
523 goto OleError;
524
525 OLECHAR Buf[MAX_OLE_STR];
526 char FileNameTmp[MAX_OLE_STR];
527 char VimCmd[MAX_OLE_STR];
528 char *s, *p;
529
530 // Prepend CTRL-\ CTRL-N to exit insert mode
531 VimCmd[0] = 0x1c;
532 VimCmd[1] = 0x0e;
533 VimCmd[2] = 0;
534
535#ifdef SINGLE_WINDOW
536 // Update the current file in Vim if it has been modified.
537 // Disabled, because it could write the file when you don't want to.
Bram Moolenaar99133032009-04-22 11:08:26 +0000538 sprintf(VimCmd + 2, ":up\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539#endif
Bram Moolenaar99133032009-04-22 11:08:26 +0000540 if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 goto OleError;
542
543 // Change Vim working directory to where the file is if desired
544 if (g_ChangeDir != CD_NONE)
Bram Moolenaar99133032009-04-22 11:08:26 +0000545 VimChangeDir(VimOle, DispatchId, FileName);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546
547 // Make Vim open the file.
548 // In the filename convert all \ to /, put a \ before a space.
Bram Moolenaar99133032009-04-22 11:08:26 +0000549 if (g_bNewTabs)
550 {
551 sprintf(VimCmd, ":tab drop ");
Bram Moolenaar17fb0e82011-08-10 17:25:51 +0200552 s = VimCmd + 10;
Bram Moolenaar99133032009-04-22 11:08:26 +0000553 }
554 else
555 {
556 sprintf(VimCmd, ":drop ");
557 s = VimCmd + 6;
558 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 sprintf(FileNameTmp, "%S", (char *)FileName);
Bram Moolenaar17fb0e82011-08-10 17:25:51 +0200560 for (p = FileNameTmp; *p != '\0' && s < VimCmd + MAX_OLE_STR - 4; ++p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561 if (*p == '\\')
562 *s++ = '/';
563 else
564 {
565 if (*p == ' ')
566 *s++ = '\\';
567 *s++ = *p;
568 }
569 *s++ = '\n';
570 *s = '\0';
571
Bram Moolenaar99133032009-04-22 11:08:26 +0000572 if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573 goto OleError;
574
575 if (LineNr > 0)
576 {
577 // Goto line
Bram Moolenaar99133032009-04-22 11:08:26 +0000578 sprintf(VimCmd, ":%d\n", LineNr);
579 if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580 goto OleError;
581 }
582
583 // Make Vim come to the foreground
Bram Moolenaar99133032009-04-22 11:08:26 +0000584 if (! VimOle.Method("SetForeground"))
585 VimOle.ErrDiag();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586
587 // We're done
588 return true;
589
590 OleError:
591 // There was an OLE error
592 // Check if it's the "unknown class string" error
Bram Moolenaar99133032009-04-22 11:08:26 +0000593 VimErrDiag(VimOle);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 return false;
595}
596
597// Return the dispatch id for the Vim method 'Method'
598// Create the Vim OLE object if necessary
599// Returns a valid dispatch id or null on error
600//
Bram Moolenaar99133032009-04-22 11:08:26 +0000601static DISPID VimGetDispatchId(COleAutomationControl& VimOle, char* Method)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602{
603 // Initialize Vim OLE connection if not already done
Bram Moolenaar99133032009-04-22 11:08:26 +0000604 if (! VimOle.IsCreated())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
Bram Moolenaar99133032009-04-22 11:08:26 +0000606 if (! VimOle.CreateObject("Vim.Application"))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 return NULL;
608 }
609
610 // Get the dispatch id for the SendKeys method.
611 // By doing this, we are checking if Vim is still there...
Bram Moolenaar99133032009-04-22 11:08:26 +0000612 DISPID DispatchId = VimOle.GetDispatchId("SendKeys");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 if (! DispatchId)
614 {
615 // We can't get a dispatch id.
616 // This means that probably Vim has been terminated.
617 // Don't issue an error message here, instead
618 // destroy the OLE object and try to connect once more
619 //
620 // In fact, this should never happen, because the OLE aut. object
621 // should not be kept long enough to allow the user to terminate Vim
622 // to avoid memory corruption (why the heck is there no system garbage
623 // collection for those damned OLE memory chunks???).
Bram Moolenaar99133032009-04-22 11:08:26 +0000624 VimOle.DeleteObject();
625 if (! VimOle.CreateObject("Vim.Application"))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 // If this create fails, it's time for an error msg
627 return NULL;
628
Bram Moolenaar99133032009-04-22 11:08:26 +0000629 if (! (DispatchId = VimOle.GetDispatchId("SendKeys")))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 // There is something wrong...
631 return NULL;
632 }
633
634 return DispatchId;
635}
636
637// Output an error message for an OLE error
638// Check on the classstring error, which probably means Vim wasn't registered.
639//
Bram Moolenaar99133032009-04-22 11:08:26 +0000640static void VimErrDiag(COleAutomationControl& VimOle)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641{
Bram Moolenaar99133032009-04-22 11:08:26 +0000642 SCODE sc = GetScode(VimOle.GetResult());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 if (sc == CO_E_CLASSSTRING)
644 {
645 char Buf[256];
Bram Moolenaar99133032009-04-22 11:08:26 +0000646 sprintf(Buf, "There is no registered OLE automation server named "
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 "\"Vim.Application\".\n"
648 "Use the OLE-enabled version of Vim with VisVim and "
649 "make sure to register Vim by running \"vim -register\".");
Bram Moolenaar99133032009-04-22 11:08:26 +0000650 MessageBox(NULL, Buf, "OLE Error", MB_OK);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 }
652 else
Bram Moolenaar99133032009-04-22 11:08:26 +0000653 VimOle.ErrDiag();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654}
655
656// Change directory to the directory the file 'FileName' is in or it's parent
657// directory according to the setting of the global 'g_ChangeDir':
658// 'FileName' is expected to contain an absolute DOS path including the drive
659// letter.
660// CD_NONE
661// CD_SOURCE_PATH
662// CD_SOURCE_PARENT
663//
Bram Moolenaar99133032009-04-22 11:08:26 +0000664static void VimChangeDir(COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665{
666 // Do a :cd first
667
668 // Get the path name of the file ("dir/")
669 CString StrFileName = FileName;
670 char Drive[_MAX_DRIVE];
671 char Dir[_MAX_DIR];
672 char DirUnix[_MAX_DIR * 2];
673 char *s, *t;
674
Bram Moolenaar99133032009-04-22 11:08:26 +0000675 _splitpath(StrFileName, Drive, Dir, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676
677 // Convert to Unix path name format, escape spaces.
678 t = DirUnix;
679 for (s = Dir; *s; ++s)
680 if (*s == '\\')
681 *t++ = '/';
682 else
683 {
684 if (*s == ' ')
685 *t++ = '\\';
686 *t++ = *s;
687 }
688 *t = '\0';
689
690
691 // Construct the cd command; append /.. if cd to parent
692 // directory and not in root directory
693 OLECHAR Buf[MAX_OLE_STR];
694 char VimCmd[MAX_OLE_STR];
695
Bram Moolenaar99133032009-04-22 11:08:26 +0000696 sprintf(VimCmd, ":cd %s%s%s\n", Drive, DirUnix,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697 g_ChangeDir == CD_SOURCE_PARENT && DirUnix[1] ? ".." : "");
Bram Moolenaar99133032009-04-22 11:08:26 +0000698 VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699}
700
701#ifdef _DEBUG
702// Print out a debug message
703//
Bram Moolenaar99133032009-04-22 11:08:26 +0000704static void DebugMsg(char* Msg, char* Arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705{
706 char Buf[400];
Bram Moolenaar99133032009-04-22 11:08:26 +0000707 sprintf(Buf, Msg, Arg);
708 AfxMessageBox(Buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709}
710#endif