2004-06-13 20:20:40 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include <comdef.h> // For _bstr_t
|
|
|
|
#include "VisVim.h"
|
|
|
|
#include "Commands.h"
|
|
|
|
#include "OleAut.h"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
#undef THIS_FILE
|
|
|
|
static char THIS_FILE[] = __FILE__;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// Change directory before opening file?
|
|
|
|
#define CD_SOURCE 0 // Cd to source path
|
|
|
|
#define CD_SOURCE_PARENT 1 // Cd to parent directory of source path
|
|
|
|
#define CD_NONE 2 // No cd
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL g_bEnableVim = TRUE; // Vim enabled
|
|
|
|
static BOOL g_bDevStudioEditor = FALSE; // Open file in Dev Studio editor simultaneously
|
|
|
|
static int g_ChangeDir = CD_NONE; // CD after file open?
|
|
|
|
|
|
|
|
static void VimSetEnableState (BOOL bEnableState);
|
|
|
|
static BOOL VimOpenFile (BSTR& FileName, long LineNr);
|
|
|
|
static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method);
|
|
|
|
static void VimErrDiag (COleAutomationControl& VimOle);
|
|
|
|
static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName);
|
|
|
|
static void DebugMsg (char* Msg, char* Arg = NULL);
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CCommands
|
|
|
|
|
|
|
|
CCommands::CCommands ()
|
|
|
|
{
|
|
|
|
// m_pApplication == NULL; M$ Code generation bug!!!
|
|
|
|
m_pApplication = NULL;
|
|
|
|
m_pApplicationEventsObj = NULL;
|
|
|
|
m_pDebuggerEventsObj = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CCommands::~CCommands ()
|
|
|
|
{
|
|
|
|
ASSERT (m_pApplication != NULL);
|
|
|
|
if (m_pApplication)
|
|
|
|
{
|
|
|
|
m_pApplication->Release ();
|
|
|
|
m_pApplication = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCommands::SetApplicationObject (IApplication * pApplication)
|
|
|
|
{
|
|
|
|
// This function assumes pApplication has already been AddRef'd
|
2007-05-10 18:46:18 +00:00
|
|
|
// for us, which CDSAddIn did in it's QueryInterface call
|
2004-06-13 20:20:40 +00:00
|
|
|
// just before it called us.
|
|
|
|
m_pApplication = pApplication;
|
|
|
|
if (! m_pApplication)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create Application event handlers
|
|
|
|
XApplicationEventsObj::CreateInstance (&m_pApplicationEventsObj);
|
|
|
|
if (! m_pApplicationEventsObj)
|
|
|
|
{
|
|
|
|
ReportInternalError ("XApplicationEventsObj::CreateInstance");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_pApplicationEventsObj->AddRef ();
|
|
|
|
m_pApplicationEventsObj->Connect (m_pApplication);
|
|
|
|
m_pApplicationEventsObj->m_pCommands = this;
|
|
|
|
|
|
|
|
#ifdef NEVER
|
|
|
|
// Create Debugger event handler
|
|
|
|
CComPtr < IDispatch > pDebugger;
|
|
|
|
if (SUCCEEDED (m_pApplication->get_Debugger (&pDebugger))
|
|
|
|
&& pDebugger != NULL)
|
|
|
|
{
|
|
|
|
XDebuggerEventsObj::CreateInstance (&m_pDebuggerEventsObj);
|
|
|
|
m_pDebuggerEventsObj->AddRef ();
|
|
|
|
m_pDebuggerEventsObj->Connect (pDebugger);
|
|
|
|
m_pDebuggerEventsObj->m_pCommands = this;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Get settings from registry HKEY_CURRENT_USER\Software\Vim\VisVim
|
|
|
|
HKEY hAppKey = GetAppKey ("Vim");
|
|
|
|
if (hAppKey)
|
|
|
|
{
|
|
|
|
HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
|
|
if (hSectionKey)
|
|
|
|
{
|
|
|
|
g_bEnableVim = GetRegistryInt (hSectionKey, "EnableVim",
|
|
|
|
g_bEnableVim);
|
|
|
|
g_bDevStudioEditor = GetRegistryInt(hSectionKey,"DevStudioEditor",
|
|
|
|
g_bDevStudioEditor);
|
|
|
|
g_ChangeDir = GetRegistryInt (hSectionKey, "ChangeDir",
|
|
|
|
g_ChangeDir);
|
|
|
|
RegCloseKey (hSectionKey);
|
|
|
|
}
|
|
|
|
RegCloseKey (hAppKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCommands::UnadviseFromEvents ()
|
|
|
|
{
|
|
|
|
ASSERT (m_pApplicationEventsObj != NULL);
|
|
|
|
if (m_pApplicationEventsObj)
|
|
|
|
{
|
|
|
|
m_pApplicationEventsObj->Disconnect (m_pApplication);
|
|
|
|
m_pApplicationEventsObj->Release ();
|
|
|
|
m_pApplicationEventsObj = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NEVER
|
|
|
|
if (m_pDebuggerEventsObj)
|
|
|
|
{
|
|
|
|
// Since we were able to connect to the Debugger events, we
|
|
|
|
// should be able to access the Debugger object again to
|
|
|
|
// unadvise from its events (thus the VERIFY_OK below--see
|
|
|
|
// stdafx.h).
|
|
|
|
CComPtr < IDispatch > pDebugger;
|
|
|
|
VERIFY_OK (m_pApplication->get_Debugger (&pDebugger));
|
|
|
|
ASSERT (pDebugger != NULL);
|
|
|
|
m_pDebuggerEventsObj->Disconnect (pDebugger);
|
|
|
|
m_pDebuggerEventsObj->Release ();
|
|
|
|
m_pDebuggerEventsObj = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Event handlers
|
|
|
|
|
|
|
|
// Application events
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::BeforeBuildStart ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::BuildFinish (long nNumErrors, long nNumWarnings)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The open document event handle is the place where the real interface work
|
|
|
|
// is done.
|
|
|
|
// Vim gets called from here.
|
|
|
|
//
|
|
|
|
HRESULT CCommands::XApplicationEvents::DocumentOpen (IDispatch * theDocument)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
|
|
|
|
if (! g_bEnableVim)
|
|
|
|
// Vim not enabled or empty command line entered
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
// First get the current file name and line number
|
|
|
|
|
|
|
|
// Get the document object
|
|
|
|
CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
|
|
|
|
if (! pDoc)
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
BSTR FileName;
|
|
|
|
long LineNr = -1;
|
|
|
|
|
|
|
|
// Get the document name
|
|
|
|
if (FAILED (pDoc->get_FullName (&FileName)))
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
LPDISPATCH pDispSel;
|
|
|
|
|
|
|
|
// Get a selection object dispatch pointer
|
|
|
|
if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
|
|
|
|
{
|
|
|
|
// Get the selection object
|
|
|
|
CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
|
|
|
|
|
|
|
|
if (pSel)
|
|
|
|
// Get the selection line number
|
|
|
|
pSel->get_CurrentLine (&LineNr);
|
|
|
|
|
|
|
|
pDispSel->Release ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the file in Vim and position to the current line
|
|
|
|
if (VimOpenFile (FileName, LineNr))
|
|
|
|
{
|
|
|
|
if (! g_bDevStudioEditor)
|
|
|
|
{
|
|
|
|
// Close the document in developer studio
|
|
|
|
CComVariant vSaveChanges = dsSaveChangesPrompt;
|
|
|
|
DsSaveStatus Saved;
|
|
|
|
|
|
|
|
pDoc->Close (vSaveChanges, &Saved);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're done here
|
|
|
|
SysFreeString (FileName);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::BeforeDocumentClose (IDispatch * theDocument)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::DocumentSave (IDispatch * theDocument)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::NewDocument (IDispatch * theDocument)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
|
|
|
|
if (! g_bEnableVim)
|
|
|
|
// Vim not enabled or empty command line entered
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
// First get the current file name and line number
|
|
|
|
|
|
|
|
CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (theDocument);
|
|
|
|
if (! pDoc)
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
BSTR FileName;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
hr = pDoc->get_FullName (&FileName);
|
|
|
|
if (FAILED (hr))
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
// Open the file in Vim and position to the current line
|
|
|
|
if (VimOpenFile (FileName, 0))
|
|
|
|
{
|
|
|
|
if (! g_bDevStudioEditor)
|
|
|
|
{
|
|
|
|
// Close the document in developer studio
|
|
|
|
CComVariant vSaveChanges = dsSaveChangesPrompt;
|
|
|
|
DsSaveStatus Saved;
|
|
|
|
|
|
|
|
pDoc->Close (vSaveChanges, &Saved);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SysFreeString (FileName);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::WindowActivate (IDispatch * theWindow)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::WindowDeactivate (IDispatch * theWindow)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::WorkspaceOpen ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::WorkspaceClose ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CCommands::XApplicationEvents::NewWorkspace ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debugger event
|
|
|
|
|
|
|
|
HRESULT CCommands::XDebuggerEvents::BreakpointHit (IDispatch * pBreakpoint)
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// VisVim dialog
|
|
|
|
|
|
|
|
class CMainDialog : public CDialog
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CMainDialog (CWnd * pParent = NULL); // Standard constructor
|
|
|
|
|
|
|
|
//{{AFX_DATA(CMainDialog)
|
|
|
|
enum { IDD = IDD_ADDINMAIN };
|
|
|
|
int m_ChangeDir;
|
|
|
|
BOOL m_bDevStudioEditor;
|
|
|
|
//}}AFX_DATA
|
|
|
|
|
|
|
|
//{{AFX_VIRTUAL(CMainDialog)
|
|
|
|
protected:
|
|
|
|
virtual void DoDataExchange (CDataExchange * pDX); // DDX/DDV support
|
|
|
|
//}}AFX_VIRTUAL
|
|
|
|
|
|
|
|
protected:
|
|
|
|
//{{AFX_MSG(CMainDialog)
|
|
|
|
afx_msg void OnEnable();
|
|
|
|
afx_msg void OnDisable();
|
|
|
|
//}}AFX_MSG
|
|
|
|
DECLARE_MESSAGE_MAP ()
|
|
|
|
};
|
|
|
|
|
|
|
|
CMainDialog::CMainDialog (CWnd * pParent /* =NULL */ )
|
|
|
|
: CDialog (CMainDialog::IDD, pParent)
|
|
|
|
{
|
|
|
|
//{{AFX_DATA_INIT(CMainDialog)
|
|
|
|
m_ChangeDir = -1;
|
|
|
|
m_bDevStudioEditor = FALSE;
|
|
|
|
//}}AFX_DATA_INIT
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMainDialog::DoDataExchange (CDataExchange * pDX)
|
|
|
|
{
|
|
|
|
CDialog::DoDataExchange (pDX);
|
|
|
|
//{{AFX_DATA_MAP(CMainDialog)
|
|
|
|
DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
|
|
|
|
DDX_Check (pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
|
|
|
|
//}}AFX_DATA_MAP
|
|
|
|
}
|
|
|
|
|
|
|
|
BEGIN_MESSAGE_MAP (CMainDialog, CDialog)
|
|
|
|
//{{AFX_MSG_MAP(CMainDialog)
|
|
|
|
//}}AFX_MSG_MAP
|
|
|
|
END_MESSAGE_MAP ()
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// CCommands methods
|
|
|
|
|
|
|
|
STDMETHODIMP CCommands::VisVimDialog ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
|
|
|
|
// Use m_pApplication to access the Developer Studio Application
|
|
|
|
// object,
|
|
|
|
// and VERIFY_OK to see error strings in DEBUG builds of your add-in
|
|
|
|
// (see stdafx.h)
|
|
|
|
|
|
|
|
VERIFY_OK (m_pApplication->EnableModeless (VARIANT_FALSE));
|
|
|
|
|
|
|
|
CMainDialog Dlg;
|
|
|
|
|
|
|
|
Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
|
|
|
|
Dlg.m_ChangeDir = g_ChangeDir;
|
|
|
|
if (Dlg.DoModal () == IDOK)
|
|
|
|
{
|
|
|
|
g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
|
|
|
|
g_ChangeDir = Dlg.m_ChangeDir;
|
|
|
|
|
|
|
|
// Save settings to registry HKEY_CURRENT_USER\Software\Vim\VisVim
|
|
|
|
HKEY hAppKey = GetAppKey ("Vim");
|
|
|
|
if (hAppKey)
|
|
|
|
{
|
|
|
|
HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
|
|
if (hSectionKey)
|
|
|
|
{
|
|
|
|
WriteRegistryInt (hSectionKey, "DevStudioEditor",
|
|
|
|
g_bDevStudioEditor);
|
|
|
|
WriteRegistryInt (hSectionKey, "ChangeDir", g_ChangeDir);
|
|
|
|
RegCloseKey (hSectionKey);
|
|
|
|
}
|
|
|
|
RegCloseKey (hAppKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_OK (m_pApplication->EnableModeless (VARIANT_TRUE));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CCommands::VisVimEnable ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
VimSetEnableState (true);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CCommands::VisVimDisable ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
VimSetEnableState (false);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CCommands::VisVimToggle ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
VimSetEnableState (! g_bEnableVim);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CCommands::VisVimLoad ()
|
|
|
|
{
|
|
|
|
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
|
|
|
|
|
|
|
|
// Use m_pApplication to access the Developer Studio Application object,
|
|
|
|
// and VERIFY_OK to see error strings in DEBUG builds of your add-in
|
|
|
|
// (see stdafx.h)
|
|
|
|
|
|
|
|
CComBSTR bStr;
|
|
|
|
// Define dispatch pointers for document and selection objects
|
|
|
|
CComPtr < IDispatch > pDispDoc, pDispSel;
|
|
|
|
|
|
|
|
// Get a document object dispatch pointer
|
|
|
|
VERIFY_OK (m_pApplication->get_ActiveDocument (&pDispDoc));
|
|
|
|
if (! pDispDoc)
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
BSTR FileName;
|
|
|
|
long LineNr = -1;
|
|
|
|
|
|
|
|
// Get the document object
|
|
|
|
CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc (pDispDoc);
|
|
|
|
|
|
|
|
if (! pDoc)
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
// Get the document name
|
|
|
|
if (FAILED (pDoc->get_FullName (&FileName)))
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
// Get a selection object dispatch pointer
|
|
|
|
if (SUCCEEDED (pDoc->get_Selection (&pDispSel)))
|
|
|
|
{
|
|
|
|
// Get the selection object
|
|
|
|
CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
|
|
|
|
|
|
|
|
if (pSel)
|
|
|
|
// Get the selection line number
|
|
|
|
pSel->get_CurrentLine (&LineNr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the file in Vim
|
|
|
|
VimOpenFile (FileName, LineNr);
|
|
|
|
|
|
|
|
SysFreeString (FileName);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Here we do the actual processing and communication with Vim
|
|
|
|
//
|
|
|
|
|
|
|
|
// Set the enable state and save to registry
|
|
|
|
//
|
|
|
|
static void VimSetEnableState (BOOL bEnableState)
|
|
|
|
{
|
|
|
|
g_bEnableVim = bEnableState;
|
|
|
|
HKEY hAppKey = GetAppKey ("Vim");
|
|
|
|
if (hAppKey)
|
|
|
|
{
|
|
|
|
HKEY hSectionKey = GetSectionKey (hAppKey, "VisVim");
|
|
|
|
if (hSectionKey)
|
|
|
|
WriteRegistryInt (hSectionKey, "EnableVim", g_bEnableVim);
|
|
|
|
RegCloseKey (hAppKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the file 'FileName' in Vim and goto line 'LineNr'
|
|
|
|
// 'FileName' is expected to contain an absolute DOS path including the drive
|
|
|
|
// letter.
|
|
|
|
// 'LineNr' must contain a valid line number or 0, e. g. for a new file
|
|
|
|
//
|
|
|
|
static BOOL VimOpenFile (BSTR& FileName, long LineNr)
|
|
|
|
{
|
|
|
|
|
|
|
|
// OLE automation object for com. with Vim
|
2007-05-10 18:46:18 +00:00
|
|
|
// When the object goes out of scope, it's destructor destroys the OLE
|
|
|
|
// connection;
|
|
|
|
// This is important to avoid blocking the object
|
2004-06-13 20:20:40 +00:00
|
|
|
// (in this memory corruption would be likely when terminating Vim
|
|
|
|
// while still running DevStudio).
|
|
|
|
// So keep this object local!
|
|
|
|
COleAutomationControl VimOle;
|
|
|
|
|
|
|
|
// :cd D:/Src2/VisVim/
|
|
|
|
//
|
|
|
|
// Get a dispatch id for the SendKeys method of Vim;
|
|
|
|
// enables connection to Vim if necessary
|
|
|
|
DISPID DispatchId;
|
|
|
|
DispatchId = VimGetDispatchId (VimOle, "SendKeys");
|
|
|
|
if (! DispatchId)
|
|
|
|
// OLE error, can't obtain dispatch id
|
|
|
|
goto OleError;
|
|
|
|
|
|
|
|
OLECHAR Buf[MAX_OLE_STR];
|
|
|
|
char FileNameTmp[MAX_OLE_STR];
|
|
|
|
char VimCmd[MAX_OLE_STR];
|
|
|
|
char *s, *p;
|
|
|
|
|
|
|
|
// Prepend CTRL-\ CTRL-N to exit insert mode
|
|
|
|
VimCmd[0] = 0x1c;
|
|
|
|
VimCmd[1] = 0x0e;
|
|
|
|
VimCmd[2] = 0;
|
|
|
|
|
|
|
|
#ifdef SINGLE_WINDOW
|
|
|
|
// Update the current file in Vim if it has been modified.
|
|
|
|
// Disabled, because it could write the file when you don't want to.
|
|
|
|
sprintf (VimCmd + 2, ":up\n");
|
|
|
|
#endif
|
|
|
|
if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
|
|
goto OleError;
|
|
|
|
|
|
|
|
// Change Vim working directory to where the file is if desired
|
|
|
|
if (g_ChangeDir != CD_NONE)
|
|
|
|
VimChangeDir (VimOle, DispatchId, FileName);
|
|
|
|
|
|
|
|
// Make Vim open the file.
|
|
|
|
// In the filename convert all \ to /, put a \ before a space.
|
|
|
|
sprintf(VimCmd, ":drop ");
|
|
|
|
sprintf(FileNameTmp, "%S", (char *)FileName);
|
|
|
|
s = VimCmd + 6;
|
|
|
|
for (p = FileNameTmp; *p != '\0' && s < FileNameTmp + MAX_OLE_STR - 4;
|
|
|
|
++p)
|
|
|
|
if (*p == '\\')
|
|
|
|
*s++ = '/';
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (*p == ' ')
|
|
|
|
*s++ = '\\';
|
|
|
|
*s++ = *p;
|
|
|
|
}
|
|
|
|
*s++ = '\n';
|
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
|
|
goto OleError;
|
|
|
|
|
|
|
|
if (LineNr > 0)
|
|
|
|
{
|
|
|
|
// Goto line
|
|
|
|
sprintf (VimCmd, ":%d\n", LineNr);
|
|
|
|
if (! VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf)))
|
|
|
|
goto OleError;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make Vim come to the foreground
|
|
|
|
if (! VimOle.Method ("SetForeground"))
|
|
|
|
VimOle.ErrDiag ();
|
|
|
|
|
|
|
|
// We're done
|
|
|
|
return true;
|
|
|
|
|
|
|
|
OleError:
|
|
|
|
// There was an OLE error
|
|
|
|
// Check if it's the "unknown class string" error
|
|
|
|
VimErrDiag (VimOle);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the dispatch id for the Vim method 'Method'
|
|
|
|
// Create the Vim OLE object if necessary
|
|
|
|
// Returns a valid dispatch id or null on error
|
|
|
|
//
|
|
|
|
static DISPID VimGetDispatchId (COleAutomationControl& VimOle, char* Method)
|
|
|
|
{
|
|
|
|
// Initialize Vim OLE connection if not already done
|
|
|
|
if (! VimOle.IsCreated ())
|
|
|
|
{
|
|
|
|
if (! VimOle.CreateObject ("Vim.Application"))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the dispatch id for the SendKeys method.
|
|
|
|
// By doing this, we are checking if Vim is still there...
|
|
|
|
DISPID DispatchId = VimOle.GetDispatchId ("SendKeys");
|
|
|
|
if (! DispatchId)
|
|
|
|
{
|
|
|
|
// We can't get a dispatch id.
|
|
|
|
// This means that probably Vim has been terminated.
|
|
|
|
// Don't issue an error message here, instead
|
|
|
|
// destroy the OLE object and try to connect once more
|
|
|
|
//
|
|
|
|
// In fact, this should never happen, because the OLE aut. object
|
|
|
|
// should not be kept long enough to allow the user to terminate Vim
|
|
|
|
// to avoid memory corruption (why the heck is there no system garbage
|
|
|
|
// collection for those damned OLE memory chunks???).
|
|
|
|
VimOle.DeleteObject ();
|
|
|
|
if (! VimOle.CreateObject ("Vim.Application"))
|
|
|
|
// If this create fails, it's time for an error msg
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (! (DispatchId = VimOle.GetDispatchId ("SendKeys")))
|
|
|
|
// There is something wrong...
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DispatchId;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output an error message for an OLE error
|
|
|
|
// Check on the classstring error, which probably means Vim wasn't registered.
|
|
|
|
//
|
|
|
|
static void VimErrDiag (COleAutomationControl& VimOle)
|
|
|
|
{
|
|
|
|
SCODE sc = GetScode (VimOle.GetResult ());
|
|
|
|
if (sc == CO_E_CLASSSTRING)
|
|
|
|
{
|
|
|
|
char Buf[256];
|
|
|
|
sprintf (Buf, "There is no registered OLE automation server named "
|
|
|
|
"\"Vim.Application\".\n"
|
|
|
|
"Use the OLE-enabled version of Vim with VisVim and "
|
|
|
|
"make sure to register Vim by running \"vim -register\".");
|
|
|
|
MessageBox (NULL, Buf, "OLE Error", MB_OK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
VimOle.ErrDiag ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change directory to the directory the file 'FileName' is in or it's parent
|
|
|
|
// directory according to the setting of the global 'g_ChangeDir':
|
|
|
|
// 'FileName' is expected to contain an absolute DOS path including the drive
|
|
|
|
// letter.
|
|
|
|
// CD_NONE
|
|
|
|
// CD_SOURCE_PATH
|
|
|
|
// CD_SOURCE_PARENT
|
|
|
|
//
|
|
|
|
static void VimChangeDir (COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName)
|
|
|
|
{
|
|
|
|
// Do a :cd first
|
|
|
|
|
|
|
|
// Get the path name of the file ("dir/")
|
|
|
|
CString StrFileName = FileName;
|
|
|
|
char Drive[_MAX_DRIVE];
|
|
|
|
char Dir[_MAX_DIR];
|
|
|
|
char DirUnix[_MAX_DIR * 2];
|
|
|
|
char *s, *t;
|
|
|
|
|
|
|
|
_splitpath (StrFileName, Drive, Dir, NULL, NULL);
|
|
|
|
|
|
|
|
// Convert to Unix path name format, escape spaces.
|
|
|
|
t = DirUnix;
|
|
|
|
for (s = Dir; *s; ++s)
|
|
|
|
if (*s == '\\')
|
|
|
|
*t++ = '/';
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (*s == ' ')
|
|
|
|
*t++ = '\\';
|
|
|
|
*t++ = *s;
|
|
|
|
}
|
|
|
|
*t = '\0';
|
|
|
|
|
|
|
|
|
|
|
|
// Construct the cd command; append /.. if cd to parent
|
|
|
|
// directory and not in root directory
|
|
|
|
OLECHAR Buf[MAX_OLE_STR];
|
|
|
|
char VimCmd[MAX_OLE_STR];
|
|
|
|
|
|
|
|
sprintf (VimCmd, ":cd %s%s%s\n", Drive, DirUnix,
|
|
|
|
g_ChangeDir == CD_SOURCE_PARENT && DirUnix[1] ? ".." : "");
|
|
|
|
VimOle.Method (DispatchId, "s", TO_OLE_STR_BUF (VimCmd, Buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
// Print out a debug message
|
|
|
|
//
|
|
|
|
static void DebugMsg (char* Msg, char* Arg)
|
|
|
|
{
|
|
|
|
char Buf[400];
|
|
|
|
sprintf (Buf, Msg, Arg);
|
|
|
|
AfxMessageBox (Buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|