/*************************************************************************** plugin_katetextfilter.cpp - description ------------------- begin : FRE Feb 23 2001 copyright : (C) 2001 by Joseph Wenninger email : jowenn@bigfoot.com ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "plugin_katetextfilter.h" #include "plugin_katetextfilter.moc" #include #include #include #include #include #include #include #include #include #include #include #include #define POP_(x) kdDebug(13000) << #x " = " << flush << x << endl #include K_EXPORT_COMPONENT_FACTORY( katetextfilterplugin, KGenericFactory( "katetextfilter" ) ) class PluginView : public KXMLGUIClient { friend class PluginKateTextFilter; public: Kate::MainWindow *win; }; PluginKateTextFilter::PluginKateTextFilter( TQObject* parent, const char* name, const TQStringList& ) : Kate::Plugin ( (Kate::Application *)parent, name ), Kate::Command(), m_pFilterShellProcess (NULL) { Kate::Document::registerCommand( this ); } PluginKateTextFilter::~PluginKateTextFilter() { delete m_pFilterShellProcess; Kate::Document::unregisterCommand( this ); } void PluginKateTextFilter::addView(Kate::MainWindow *win) { // TODO: doesn't this have to be deleted? PluginView *view = new PluginView (); (void) new TDEAction ( i18n("Filter Te&xt..."), /*"edit_filter",*/ CTRL + Key_Backslash, this, TQ_SLOT( slotEditFilter() ), view->actionCollection(), "edit_filter" ); view->setInstance (new TDEInstance("kate")); view->setXMLFile( "plugins/katetextfilter/ui.rc" ); win->guiFactory()->addClient (view); view->win = win; m_views.append (view); } void PluginKateTextFilter::removeView(Kate::MainWindow *win) { for (uint z=0; z < m_views.count(); z++) if (m_views.at(z)->win == win) { PluginView *view = m_views.at(z); m_views.remove (view); win->guiFactory()->removeClient (view); delete view; } } void splitString (TQString q, char c, TQStringList &list) // PCP { // screw the OnceAndOnlyOnce Principle! int pos; TQString item; while ( (pos = q.find(c)) >= 0) { item = q.left(pos); list.append(item); q.remove(0,pos+1); } list.append(q); } static void // PCP slipInNewText (Kate::View & view, TQString pre, TQString marked, TQString post, bool reselect) { uint preDeleteLine = 0, preDeleteCol = 0; view.cursorPosition (&preDeleteLine, &preDeleteCol); if (marked.length() > 0) view.keyDelete (); uint line = 0, col = 0; view.cursorPosition (&line, &col); view.insertText (pre + marked + post); // all this muck to leave the cursor exactly where the user // put it... // Someday we will can all this (unless if it already // is canned and I didn't find it...) // The second part of the if disrespects the display bugs // when we try to reselect. TODO: fix those bugs, and we can // un-break this if... // TODO: fix OnceAndOnlyOnce between this module and plugin_katehtmltools.cpp if (reselect && preDeleteLine == line && -1 == marked.find ('\n')) if (preDeleteLine == line && preDeleteCol == col) { view.setCursorPosition (line, col + pre.length () + marked.length () - 1); for (int x (marked.length()); x--;) view.shiftCursorLeft (); } else { view.setCursorPosition (line, col += pre.length ()); for (int x (marked.length()); x--;) view.shiftCursorRight (); } } static TQString // PCP KatePrompt ( const TQString & strTitle, const TQString & strPrompt, TQWidget * that, TQStringList *completionList ) { // TODO: Make this a "memory edit" field with a combo box // containing prior entries KLineEditDlg dlg(strPrompt, TQString(), that); dlg.setCaption(strTitle); TDECompletion *comple=dlg.lineEdit()->completionObject(); comple->setItems(*completionList); if (dlg.exec()) { if (!dlg.text().isEmpty()) { comple->addItem(dlg.text()); (*completionList)=comple->items(); } return dlg.text(); } else return ""; } void PluginKateTextFilter::slotFilterReceivedStdout (TDEProcess * pProcess, char * got, int len) { assert (pProcess == m_pFilterShellProcess); if (got && len) { // TODO: got a better idea? // while (len--) m_strFilterOutput += *got++; m_strFilterOutput += TQString::fromLocal8Bit( got, len ); // POP_(m_strFilterOutput); } } void PluginKateTextFilter::slotFilterReceivedStderr (TDEProcess * pProcess, char * got, int len) { slotFilterReceivedStdout (pProcess, got, len); } void PluginKateTextFilter::slotFilterProcessExited (TDEProcess * pProcess) { assert (pProcess == m_pFilterShellProcess); Kate::View * kv (application()->activeMainWindow()->viewManager()->activeView()); if (!kv) return; KTextEditor::EditInterfaceExt *ext=KTextEditor::editInterfaceExt(kv->getDoc()); if (ext) ext->editBegin(); TQString marked = kv->getDoc()->selection (); if (marked.length() > 0) kv -> keyDelete (); kv -> insertText (m_strFilterOutput); if (ext) ext->editEnd(); // slipInNewText (*kv, "", m_strFilterOutput, "", false); m_strFilterOutput = ""; } static void // PCP slipInFilter (KShellProcess & shell, Kate::View & view, TQString command) { TQString marked = view.getDoc()->selection (); if( marked.isEmpty()) return; // POP_(command.latin1 ()); shell.clearArguments (); shell << command; shell.start (TDEProcess::NotifyOnExit, TDEProcess::All); shell.writeStdin (marked.local8Bit (), marked.length ()); // TODO: Put up a modal dialog to defend the text from further // keystrokes while the command is out. With a cancel button... } void PluginKateTextFilter::slotFilterCloseStdin (TDEProcess * pProcess) { assert (pProcess == m_pFilterShellProcess); pProcess -> closeStdin (); } void PluginKateTextFilter::slotEditFilter () // PCP { if (!kapp->authorize("shell_access")) { KMessageBox::sorry(0,i18n( "You are not allowed to execute arbitrary external applications. If " "you want to be able to do this, contact your system administrator."), i18n("Access Restrictions")); return; } if (!application()->activeMainWindow()) return; Kate::View * kv (application()->activeMainWindow()->viewManager()->activeView()); if (!kv) return; TQString text ( KatePrompt ( i18n("Filter"), i18n("Enter command to pipe selected text through:"), (TQWidget*) kv, &completionList ) ); if ( !text.isEmpty () ) runFilter( kv, text ); } void PluginKateTextFilter::runFilter( Kate::View *kv, const TQString &filter ) { m_strFilterOutput = ""; if (!m_pFilterShellProcess) { m_pFilterShellProcess = new KShellProcess; connect ( m_pFilterShellProcess, TQ_SIGNAL(wroteStdin(TDEProcess *)), this, TQ_SLOT(slotFilterCloseStdin (TDEProcess *))); connect ( m_pFilterShellProcess, TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), this, TQ_SLOT(slotFilterReceivedStdout(TDEProcess*,char*,int)) ); connect ( m_pFilterShellProcess, TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)), this, TQ_SLOT(slotFilterReceivedStderr(TDEProcess*,char*,int)) ); connect ( m_pFilterShellProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(slotFilterProcessExited(TDEProcess*) ) ) ; } slipInFilter (*m_pFilterShellProcess, *kv, filter); } //BEGIN Kate::Command methods TQStringList PluginKateTextFilter::cmds() { return TQStringList("textfilter"); } bool PluginKateTextFilter::help( Kate::View *, const TQString&, TQString &msg ) { msg = i18n( "

Usage: textfilter COMMAND

" "

Replace the selection with the output of the specified shell command.

"); return true; } bool PluginKateTextFilter::exec( Kate::View *v, const TQString &cmd, TQString &msg ) { if (! v->getDoc()->hasSelection() ) { msg = i18n("You need to have a selection to use textfilter"); return false; } TQString filter = cmd.section( " ", 1 ).stripWhiteSpace(); if ( filter.isEmpty() ) { msg = i18n("Usage: textfilter COMMAND"); return false; } runFilter( v, filter ); return true; } //END