#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
#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; static BOOL g_bDevStudioEditor = FALSE; static BOOL g_bNewTabs = FALSE;
static int g_ChangeDir = CD_NONE;
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()
{
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)
{
m_pApplication = pApplication;
if (! m_pApplication)
return;
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
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
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_bNewTabs = GetRegistryInt(hSectionKey, "NewTabs",
g_bNewTabs);
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)
{
CComPtr < IDispatch > pDebugger;
VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
ASSERT(pDebugger != NULL);
m_pDebuggerEventsObj->Disconnect(pDebugger);
m_pDebuggerEventsObj->Release();
m_pDebuggerEventsObj = NULL;
}
#endif
}
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;
}
HRESULT CCommands::XApplicationEvents::DocumentOpen(IDispatch * theDocument)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (! g_bEnableVim)
return S_OK;
CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
if (! pDoc)
return S_OK;
BSTR FileName;
long LineNr = -1;
if (FAILED(pDoc->get_FullName(&FileName)))
return S_OK;
LPDISPATCH pDispSel;
if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
{
CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
if (pSel)
pSel->get_CurrentLine(&LineNr);
pDispSel->Release();
}
if (VimOpenFile(FileName, LineNr))
{
if (! g_bDevStudioEditor)
{
CComVariant vSaveChanges = dsSaveChangesPrompt;
DsSaveStatus Saved;
pDoc->Close(vSaveChanges, &Saved);
}
}
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)
return S_OK;
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;
if (VimOpenFile(FileName, 0))
{
if (! g_bDevStudioEditor)
{
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;
}
HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch * pBreakpoint)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return S_OK;
}
class CMainDialog : public CDialog
{
public:
CMainDialog(CWnd * pParent = NULL);
enum { IDD = IDD_ADDINMAIN };
int m_ChangeDir;
BOOL m_bDevStudioEditor;
BOOL m_bNewTabs;
protected:
virtual void DoDataExchange(CDataExchange * pDX);
protected:
afx_msg void OnEnable();
afx_msg void OnDisable();
DECLARE_MESSAGE_MAP()
};
CMainDialog::CMainDialog(CWnd * pParent )
: CDialog(CMainDialog::IDD, pParent)
{
m_ChangeDir = -1;
m_bDevStudioEditor = FALSE;
m_bNewTabs = FALSE;
}
void CMainDialog::DoDataExchange(CDataExchange * pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Radio(pDX, IDC_CD_SOURCE_PATH, m_ChangeDir);
DDX_Check(pDX, IDC_DEVSTUDIO_EDITOR, m_bDevStudioEditor);
DDX_Check(pDX, IDC_NEW_TABS, m_bNewTabs);
}
BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
END_MESSAGE_MAP()
STDMETHODIMP CCommands::VisVimDialog()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
CMainDialog Dlg;
Dlg.m_bDevStudioEditor = g_bDevStudioEditor;
Dlg.m_bNewTabs = g_bNewTabs;
Dlg.m_ChangeDir = g_ChangeDir;
if (Dlg.DoModal() == IDOK)
{
g_bDevStudioEditor = Dlg.m_bDevStudioEditor;
g_bNewTabs = Dlg.m_bNewTabs;
g_ChangeDir = Dlg.m_ChangeDir;
HKEY hAppKey = GetAppKey("Vim");
if (hAppKey)
{
HKEY hSectionKey = GetSectionKey(hAppKey, "VisVim");
if (hSectionKey)
{
WriteRegistryInt(hSectionKey, "DevStudioEditor",
g_bDevStudioEditor);
WriteRegistryInt(hSectionKey, "NewTabs",
g_bNewTabs);
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());
CComBSTR bStr;
CComPtr < IDispatch > pDispDoc, pDispSel;
VERIFY_OK(m_pApplication->get_ActiveDocument(&pDispDoc));
if (! pDispDoc)
return S_OK;
BSTR FileName;
long LineNr = -1;
CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(pDispDoc);
if (! pDoc)
return S_OK;
if (FAILED(pDoc->get_FullName(&FileName)))
return S_OK;
if (SUCCEEDED(pDoc->get_Selection(&pDispSel)))
{
CComQIPtr < ITextSelection, &IID_ITextSelection > pSel(pDispSel);
if (pSel)
pSel->get_CurrentLine(&LineNr);
}
VimOpenFile(FileName, LineNr);
SysFreeString(FileName);
return S_OK;
}
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);
}
}
static BOOL VimOpenFile(BSTR& FileName, long LineNr)
{
COleAutomationControl VimOle;
DISPID DispatchId;
DispatchId = VimGetDispatchId(VimOle, "SendKeys");
if (! DispatchId)
goto OleError;
OLECHAR Buf[MAX_OLE_STR];
char FileNameTmp[MAX_OLE_STR];
char VimCmd[MAX_OLE_STR];
char *s, *p;
VimCmd[0] = 0x1c;
VimCmd[1] = 0x0e;
VimCmd[2] = 0;
#ifdef SINGLE_WINDOW
sprintf(VimCmd + 2, ":up\n");
#endif
if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
goto OleError;
if (g_ChangeDir != CD_NONE)
VimChangeDir(VimOle, DispatchId, FileName);
if (g_bNewTabs)
{
sprintf(VimCmd, ":tab drop ");
s = VimCmd + 10;
}
else
{
sprintf(VimCmd, ":drop ");
s = VimCmd + 6;
}
sprintf(FileNameTmp, "%S", (char *)FileName);
for (p = FileNameTmp; *p != '\0' && s < VimCmd + 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)
{
sprintf(VimCmd, ":%ld\n", LineNr);
if (! VimOle.Method(DispatchId, "s", TO_OLE_STR_BUF(VimCmd, Buf)))
goto OleError;
}
if (! VimOle.Method("SetForeground"))
VimOle.ErrDiag();
return true;
OleError:
VimErrDiag(VimOle);
return false;
}
static DISPID VimGetDispatchId(COleAutomationControl& VimOle, char* Method)
{
if (! VimOle.IsCreated())
{
if (! VimOle.CreateObject("Vim.Application"))
return NULL;
}
DISPID DispatchId = VimOle.GetDispatchId("SendKeys");
if (! DispatchId)
{
VimOle.DeleteObject();
if (! VimOle.CreateObject("Vim.Application"))
return NULL;
if (! (DispatchId = VimOle.GetDispatchId("SendKeys")))
return NULL;
}
return DispatchId;
}
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();
}
static void VimChangeDir(COleAutomationControl& VimOle, DISPID DispatchId, BSTR& FileName)
{
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);
t = DirUnix;
for (s = Dir; *s; ++s)
if (*s == '\\')
*t++ = '/';
else
{
if (*s == ' ')
*t++ = '\\';
*t++ = *s;
}
*t = '\0';
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
static void DebugMsg(char* Msg, char* Arg)
{
char Buf[400];
sprintf(Buf, Msg, Arg);
AfxMessageBox(Buf);
}
#endif