home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / visvile / commands.cpp next >
C/C++ Source or Header  |  1998-09-07  |  14KB  |  485 lines

  1. // Commands.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "VisVile.h"
  6. #include "Commands.h"
  7.  
  8. #include <initguid.h>
  9. #include "oleauto.h"
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <direct.h>
  15. #include <io.h>
  16.  
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. static char workspace_cwd[FILENAME_MAX + 1];
  24.  
  25. typedef struct openfile_opts_struct
  26. {
  27.     BOOL goto_line_number;         /* T -> extract document line number from
  28.                                     * current docu selection.
  29.                                     */
  30.     BOOL ck_document_error;        /* T -> If can't open document, report
  31.                                     * error, else assume that error indicates
  32.                                     * attempt to open non-TEXT document.
  33.                                     */
  34.     BOOL honor_addin_state;        /* T -> If addin disabled, do nothing. */
  35.     BOOL never_close;              /* T -> regardless of current configuration,
  36.                                     * don't close the devstudio editor's copy
  37.                                     * of the open document.
  38.                                     */
  39.  
  40. } OPENFILE_OPTS;
  41.  
  42. /////////////////////////////////////////////////////////////////////////////
  43. // CCommands
  44.  
  45. CCommands::CCommands()
  46. {
  47.     m_pApplication          = NULL;
  48.     m_pApplicationEventsObj = NULL;
  49.     m_pDebuggerEventsObj    = NULL;
  50. }
  51.  
  52. CCommands::~CCommands()
  53. {
  54.     if (m_pApplication)
  55.         m_pApplication->Release();
  56. }
  57.  
  58. BOOL CCommands::SetApplicationObject(IApplication* pApplication)
  59. {
  60.     // This function assumes pApplication has already been AddRef'd
  61.     //  for us, which CDSAddIn did in its QueryInterface call
  62.     //  just before it called us.
  63.     m_pApplication = pApplication;
  64.  
  65.     // Create Application event handlers
  66.     XApplicationEventsObj::CreateInstance(&m_pApplicationEventsObj);
  67.     if (m_pApplicationEventsObj)
  68.     {
  69.         m_pApplicationEventsObj->AddRef();
  70.         m_pApplicationEventsObj->Connect(m_pApplication);
  71.         m_pApplicationEventsObj->m_pCommands = this;
  72.     }
  73.     else
  74.         return (FALSE);
  75.  
  76. #ifdef WANT_DEBUGGER_EVENTS
  77.     // Create Debugger event handler
  78.     // FIXME -- stupid code, assumes no errors
  79.     CComPtr<IDispatch> pDebugger;
  80.     if (SUCCEEDED(m_pApplication->get_Debugger(&pDebugger))
  81.         && pDebugger != NULL)
  82.     {
  83.         XDebuggerEventsObj::CreateInstance(&m_pDebuggerEventsObj);
  84.         m_pDebuggerEventsObj->AddRef();
  85.         m_pDebuggerEventsObj->Connect(pDebugger);
  86.         m_pDebuggerEventsObj->m_pCommands = this;
  87.     }
  88. #endif
  89.     return (TRUE);
  90. }
  91.  
  92. void CCommands::UnadviseFromEvents()
  93. {
  94.     if (m_pApplicationEventsObj)
  95.     {
  96.         m_pApplicationEventsObj->Disconnect(m_pApplication);
  97.         m_pApplicationEventsObj->Release();
  98.         m_pApplicationEventsObj = NULL;
  99.     }
  100.  
  101. #ifdef WANT_DEBUGGER_EVENTS
  102.     if (m_pDebuggerEventsObj != NULL)
  103.     {
  104.         // Since we were able to connect to the Debugger events, we
  105.         //  should be able to access the Debugger object again to
  106.         //  unadvise from its events (thus the VERIFY_OK below--see stdafx.h).
  107.         CComPtr<IDispatch> pDebugger;
  108.         VERIFY_OK(m_pApplication->get_Debugger(&pDebugger));
  109.         ASSERT (pDebugger != NULL);
  110.         m_pDebuggerEventsObj->Disconnect(pDebugger);
  111.         m_pDebuggerEventsObj->Release();
  112.         m_pDebuggerEventsObj = NULL;
  113.     }
  114. #endif
  115. }
  116.  
  117.  
  118. /////////////////////////////////////////////////////////////////////////////
  119. // Event handlers
  120.  
  121. static void
  122. save_workspace_cwd(void)
  123. {
  124.     if (_getcwd(workspace_cwd, sizeof(workspace_cwd)) == NULL)
  125.         workspace_cwd[0] = '\0';  // I suppose this might happen
  126. }
  127.  
  128. static HRESULT
  129. fetch_workspace_logname(CCommands *cmdp, char *file)
  130. {
  131.     BSTR                bstr_prjname;
  132.     HRESULT             hr;
  133.     CComPtr <IDispatch> pDispProj;
  134.  
  135.     hr = cmdp->GetApplicationObject()->get_ActiveProject(&pDispProj);
  136.     if (FAILED(hr))
  137.         return (ReportLastError(hr));
  138.     CComQIPtr < IGenericProject, &IID_IGenericProject > pProj(pDispProj);
  139.     if (! pProj)
  140.     {
  141.         ::MessageBox(NULL,
  142.          "Unexpected OLE error:  Unable to access current project object",
  143.                      PROGNAM,
  144.                      MB_OK|MB_ICONSTOP);
  145.         return (E_UNEXPECTED);
  146.     }
  147.     hr  = pProj->get_Name(&bstr_prjname);
  148.     if (FAILED(hr))
  149.         return (ReportLastError(hr));
  150.     sprintf(file, "%S.plg", bstr_prjname);
  151.     SysFreeString(bstr_prjname);
  152.     if (workspace_cwd[0] == '\0')
  153.         save_workspace_cwd();  // as a side effect, update workspace cwd
  154.                                // when necessary (should not be necessary).
  155.     return (hr);
  156. }
  157.  
  158. static HRESULT
  159. unexpected_docu_error(void)
  160. {
  161.     ::MessageBox(NULL,
  162.      "Unexpected OLE error:  VisVile->DevStudio document connection failed.",
  163.                  PROGNAM,
  164.                  MB_OK|MB_ICONSTOP);
  165.     return (E_UNEXPECTED);
  166. }
  167.  
  168. static HRESULT
  169. openfile(IDispatch *theDocument, OPENFILE_OPTS *opts)
  170. {
  171.     BSTR    filename;
  172.     HRESULT hr;
  173.     long    lineno = -1;
  174.  
  175.     if (opts->honor_addin_state && ! visvile_opts.enabled)
  176.         return (S_OK);
  177.  
  178.     // Process file _if_ a Text Document
  179.     CComQIPtr < IGenericDocument, &IID_IGenericDocument > pGenDoc(theDocument);
  180.     if (! pGenDoc)
  181.         return ((opts->ck_document_error) ? unexpected_docu_error() : S_OK);
  182.     else
  183.     {
  184.         BSTR doc_type;
  185.         int  not_text;
  186.  
  187.         hr = pGenDoc->get_Type(&doc_type);
  188.         if (FAILED(hr))
  189.             return (ReportLastError(hr));
  190.         not_text = (wcscmp(doc_type, L"Text") != 0);
  191.         SysFreeString(doc_type);
  192.         if (not_text)
  193.             return (S_OK);
  194.     }
  195.  
  196.     // Okay, get the text document object
  197.     CComQIPtr < ITextDocument, &IID_ITextDocument > pDoc(theDocument);
  198.     if (! pDoc)
  199.         return ((opts->ck_document_error) ? unexpected_docu_error() : S_OK);
  200.  
  201.     // Get the document name
  202.     hr = pDoc->get_FullName(&filename);
  203.     if (FAILED(hr))
  204.         return (ReportLastError(hr));
  205.  
  206.     if (opts->goto_line_number)
  207.     {
  208.         LPDISPATCH pDispSel;
  209.  
  210.         // Get a selection object dispatch pointer
  211.         if (SUCCEEDED (pDoc->get_Selection(&pDispSel)))
  212.         {
  213.             // Get the selection object
  214.             CComQIPtr < ITextSelection, &IID_ITextSelection > pSel (pDispSel);
  215.  
  216.             if (pSel) // Get the selection line number
  217.                 pSel->get_CurrentLine(&lineno);
  218.  
  219.             pDispSel->Release();
  220.         }
  221.         // Else winvile will open file at BOF.
  222.     }
  223.  
  224.     if (! opts->never_close && visvile_opts.close_ds_doc)
  225.     {
  226.         // Close the document in developer studio
  227.  
  228.         CComVariant vSaveChanges = dsSaveChangesPrompt;
  229.         DsSaveStatus Saved;
  230.  
  231.         pDoc->Close(vSaveChanges, &Saved);
  232.     }
  233.  
  234.     // Open the file in Winvile and position to the selected line
  235.     hr = pVile->FileOpen(filename, lineno);
  236.     SysFreeString(filename);
  237.     if (FAILED(hr))
  238.         ReportLastError(hr);
  239.     return (hr);
  240. }
  241.  
  242. // Application events
  243.  
  244. HRESULT CCommands::XApplicationEvents::BeforeBuildStart()
  245. {
  246.     HRESULT hr = S_OK;
  247.  
  248.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  249.     if (visvile_opts.enabled)
  250.     {
  251.         if (visvile_opts.write_buffers)
  252.         {
  253.             /*
  254.              * The following cryptic vile command flushes all modified
  255.              * buffers to disk and does not prompt for user response.
  256.              *
  257.              * Note:  because DevStudio decides what files need to be
  258.              * rebuilt _before_ this event is fired, the "write_buffers"
  259.              * option isn't quite as useful as it might seem.  As a
  260.              * workaround, press the "build" button/key (F7) twice :-) .
  261.              * See ../doc/visvile.doc for further details.
  262.              */
  263.  
  264.             hr = pVile->VileCmd("1:ww\n", FALSE, FALSE);
  265.             if (FAILED(hr))
  266.                 ReportLastError(hr);
  267.         }
  268.         if (visvile_opts.sync_errbuf)
  269.         {
  270.             char logpath[FILENAME_MAX + 1], file[FILENAME_MAX + 1];
  271.  
  272.             /*
  273.              * The build log (activated from the Tools -> Options -> Build
  274.              * dialog box) may be accessed using this path:
  275.              *
  276.              * <workspace_cwd>\\<workspace_logname>
  277.              */
  278.  
  279.             hr = fetch_workspace_logname(m_pCommands, file);
  280.             if (SUCCEEDED(hr))
  281.             {
  282.                 sprintf(logpath, "%s\\%s", workspace_cwd, file);
  283.  
  284.                 /*
  285.                  * Nuke old logfile to ensure that the "wait-file" winvile
  286.                  * command invoked by BuildFinish() below picks up a fresh
  287.                  * logfile.
  288.                  */
  289.                 (void) remove(logpath);
  290.             }
  291.         }
  292.     }
  293.     return (hr);
  294. }
  295.  
  296. HRESULT
  297. CCommands::XApplicationEvents::BuildFinish(long nNumErrors, long nNumWarnings)
  298. {
  299.     HRESULT hr = S_OK;
  300.  
  301.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  302.     if (visvile_opts.enabled &&
  303.                         visvile_opts.sync_errbuf &&
  304.                                     (nNumErrors || nNumWarnings))
  305.     {
  306.         char cmd[FILENAME_MAX * 5 + 1],
  307.              path[FILENAME_MAX + 1],
  308.              file[FILENAME_MAX + 1];
  309.  
  310.         /*
  311.          * Suck the current active project's build log into winvile's error
  312.          * buffer.  If the build log doesn't exist, the user will be annoyed
  313.          * by an editor that pops up an empty buffer :-) .
  314.          *
  315.          * The build log (activated from the Tools -> Options -> Build dialog
  316.          * box) may be accessed using this path:
  317.          *
  318.          *    <workspace_cwd>\\<workspace_logname>
  319.          */
  320.         hr = fetch_workspace_logname(m_pCommands, file);
  321.         if (SUCCEEDED(hr))
  322.         {
  323.             sprintf(path, "%s\\%s", workspace_cwd, file);
  324.             sprintf(cmd,
  325.          ":e [History]\n:kill %s\n:wait-file %s\n:view %s\n:error-buffer %s\n",
  326.                     file,
  327.                     path,
  328.                     path,
  329.                     file);
  330.             pVile->VileCmd(cmd, TRUE, TRUE);
  331.         }
  332.     }
  333.     return (hr);
  334. }
  335.  
  336. HRESULT CCommands::XApplicationEvents::BeforeApplicationShutDown()
  337. {
  338.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  339.     return S_OK;
  340. }
  341.  
  342. HRESULT
  343. CCommands::XApplicationEvents::DocumentOpen(IDispatch* theDocument)
  344. {
  345.     OPENFILE_OPTS opts;
  346.  
  347.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  348.     opts.goto_line_number  = TRUE;
  349.     opts.ck_document_error = TRUE;
  350.     opts.honor_addin_state = TRUE;
  351.     opts.never_close       = FALSE;
  352.     return (openfile(theDocument, &opts));
  353. }
  354.  
  355. HRESULT CCommands::XApplicationEvents::BeforeDocumentClose(IDispatch* theDocument)
  356. {
  357.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  358.     return S_OK;
  359. }
  360.  
  361. HRESULT CCommands::XApplicationEvents::DocumentSave(IDispatch* theDocument)
  362. {
  363.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  364.     return S_OK;
  365. }
  366.  
  367. HRESULT CCommands::XApplicationEvents::NewDocument(IDispatch* theDocument)
  368. {
  369.     OPENFILE_OPTS opts;
  370.  
  371.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  372.     opts.goto_line_number  = FALSE;
  373.     opts.ck_document_error = TRUE;
  374.     opts.honor_addin_state = TRUE;
  375.     opts.never_close       = FALSE;
  376.     return (openfile(theDocument, &opts));
  377. }
  378.  
  379. HRESULT CCommands::XApplicationEvents::WindowActivate(IDispatch* theWindow)
  380. {
  381.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  382.     return S_OK;
  383. }
  384.  
  385. HRESULT CCommands::XApplicationEvents::WindowDeactivate(IDispatch* theWindow)
  386. {
  387.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  388.     return S_OK;
  389. }
  390.  
  391. HRESULT CCommands::XApplicationEvents::WorkspaceOpen()
  392. {
  393.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  394.     save_workspace_cwd();
  395.     return (S_OK);
  396. }
  397.  
  398. HRESULT CCommands::XApplicationEvents::WorkspaceClose()
  399. {
  400.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  401.     workspace_cwd[0] = '\0';     // Erase saved cwd.
  402.     return (S_OK);
  403. }
  404.  
  405. HRESULT CCommands::XApplicationEvents::NewWorkspace()
  406. {
  407.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  408.     save_workspace_cwd();
  409.     return (S_OK);
  410. }
  411.  
  412. // Debugger event
  413. HRESULT CCommands::XDebuggerEvents::BreakpointHit(IDispatch* pBreakpoint)
  414. {
  415.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  416.     return S_OK;
  417. }
  418.  
  419.  
  420. /////////////////////////////////////////////////////////////////////////////
  421. // CCommands methods
  422.  
  423. STDMETHODIMP CCommands::VisVileConfig()
  424. {
  425.     CConfigDlg Dlg;
  426.  
  427.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  428.     m_pApplication->EnableModeless(VARIANT_FALSE);
  429.     if (Dlg.DoModal() == IDOK)
  430.     {
  431.         visvile_regdata_dirty();   // Be sloppy & assume user changed cfg.
  432.         visvile_opts.cd_doc_dir    = Dlg.m_cd_doc_dir;
  433.         visvile_opts.close_ds_doc  = Dlg.m_close_ds_doc;
  434.         visvile_opts.enabled       = Dlg.m_enabled;
  435.         visvile_opts.sync_errbuf   = Dlg.m_sync_errbuf;
  436.         visvile_opts.write_buffers = Dlg.m_write_buffers;
  437.     }
  438.     m_pApplication->EnableModeless(VARIANT_TRUE);
  439.     return S_OK;
  440. }
  441.  
  442. STDMETHODIMP CCommands::VisVileEnable()
  443. {
  444.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  445.     if (! visvile_opts.enabled)
  446.     {
  447.         visvile_opts.enabled = TRUE;
  448.         visvile_regdata_dirty();
  449.     }
  450.     return S_OK;
  451. }
  452.  
  453. STDMETHODIMP CCommands::VisVileDisable()
  454. {
  455.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  456.     if (visvile_opts.enabled)
  457.     {
  458.         visvile_opts.enabled = FALSE;
  459.         visvile_regdata_dirty();
  460.     }
  461.     return S_OK;
  462. }
  463.  
  464. STDMETHODIMP CCommands::VisVileOpenDoc()
  465. {
  466.     HRESULT       hr;
  467.     OPENFILE_OPTS opts;
  468.  
  469.     AFX_MANAGE_STATE(AfxGetStaticModuleState());
  470.  
  471.     // Define dispatch pointers for document and selection objects
  472.     CComPtr < IDispatch > pDispDoc;
  473.  
  474.     // Get a document object dispatch pointer
  475.     hr = m_pApplication->get_ActiveDocument(&pDispDoc);
  476.     if (FAILED(hr))
  477.         return (ReportLastError(hr));
  478.  
  479.     opts.goto_line_number  = TRUE;
  480.     opts.ck_document_error = FALSE;
  481.     opts.honor_addin_state = FALSE;
  482.     opts.never_close       = TRUE;
  483.     return (openfile(pDispDoc, &opts));
  484. }
  485.