Logo Search packages:      
Sourcecode: yzis version File versions  Download package

session.cpp

/* This file is part of the Yzis libraries
*  Copyright (C) 2003-2005 Mickael Marchand <mikmak@yzis.org>,
*  Copyright (C) 2003-2004 Thomas Capricelli <orzel@freehackers.org>
*  Copyright (C) 2005      Scott Newton <scottn@ihug.co.nz>
*  Copyright (C) 2006-2007 Philippe Fremy <phil at freehackers dot org>
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Library General Public
*  License as published by the Free Software Foundation; either
*  version 2 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Library General Public License for more details.
*
*  You should have received a copy of the GNU Library General Public License
*  along with this library; see the file COPYING.LIB.  If not, write to
*  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
*  Boston, MA 02110-1301, USA.
**/

// Project
#include "session.h"

#include "yzis.h"
#include "debug.h"
#include "kate/schema.h"
#include "buffer.h"
#include "registers.h"
#include "mapping.h"
#include "search.h"
#include "events.h"
#include "internal_options.h"
#include "view.h"
#include "yzisinfo.h"
#include "resourcemgr.h"
#include "luaengine.h"

// system
#include <stdlib.h>

// Qt
#include <QCoreApplication>
#include <QDir>
#include <QTimer>
#include <QDateTime>
#include <QFile>
#include <QStringList>
#include <QBuffer>

// project
#include "mode_pool.h"
#include "mode_command.h"
#include "mode_complete.h"
#include "mode_ex.h"
#include "mode_insert.h"
#include "mode_search.h"
#include "mode_visual.h"

using namespace yzis;

#include "tags_stack.h"

#define dbg()    yzDebug("YSession")
#define err()    yzError("YSession")
#define ftl()    yzFatal("YSession")

00069 YSessionIface::~YSessionIface()
{
    // nothing to do here
}

YSession* YSession::mInstance = 0;

00076 void YSession::initDebug( int argc, char ** argv )
{
    // initDebug() must be run early in the creation process
    YDebugBackend::self()->parseRcfile( DEBUGRC_FNAME );
    YDebugBackend::self()->parseArgv( argc, argv );
    dbg() << " ==============[ Yzis started at: " << QDateTime::currentDateTime().toString() << "]====================" << endl;
}

00084 YSession * YSession::self()
{
    if (mInstance == 0L) {
        err() << "YSession::setInstance() has not been called" << endl;
        err() << "There is currently no instance of the session" << endl;
        err() << "Expect SEGFAULT as the next thing to happen!" << endl;
    }
    return mInstance;
}

00094 void YSession::setInstance(YSession* instance)
{
    dbg().SPrintf("setInstance( %p )", (void *) instance );
    mInstance = instance;
    mInstance->init();
}

00101 YSession::YSession()
{
    dbg() << "YSession()" << endl;
    // do not use debug code here because debug backend is not initialised yet
}

00107 void YSession::init()
{
    dbg() << "init()" << endl;
    initLanguage();
    initModes();
    initResource();

    YZIS_SAFE_MODE {
        dbg() << "Yzis SAFE MODE enabled." << endl;
    }
    mSearch = new YSearch();
    mCurView = 0;
    mCurBuffer = 0;
    events = new YEvents();
    mSchemaManager = new YzisSchemaManager();
    mOptions = new YInternalOptionPool();
    mRegisters = new YRegisters();
    mYzisinfo = new YInfo();
    mTagStack = new YTagStack;

    initScript();
    // mYzisinfo->read(this);

    // create HlManager right from the beginning to ensure that this isn't
    // done in YSession::~YSession
    YzisHlManager::self();
    dbg() << "init() done" << endl;
}

00136 void YSession::initLanguage()
{
    setlocale( LC_ALL, "");
#ifndef YZIS_WIN32_GCC
    bindtextdomain( "yzis", QString("%1%2").arg( PREFIX ).arg("/share/locale").toUtf8().data() );
    bind_textdomain_codeset( "yzis", "UTF-8" );
    textdomain( "yzis" );
#endif
}

00146 void YSession::initResource()
{
    mResourceMgr = new YResourceMgr();
}

00151 void YSession::initScript()
{
    QString resource;
    resource = resourceMgr()->findResource( ConfigScriptResource, "init.lua" );
    if (! resource.isEmpty()) {
        YLuaEngine::self()->source( resource );
    }
}

00160 void YSession::parseCommandLine( int argc, char * argv[] )
{
    QStringList args;
    YView* first = NULL;
    YView* v;
    QString s;

    for ( int i = 0; i < argc; i++) args << argv[i];

    //quick and very durty way to remove debug args from the args list
    //needed to avoid nyzis to find "unknown options"
    YDebugBackend::self()->parseArgv( args );

    for ( int i = 1; i < args.count(); ++i ) {
        if ( args.at(i)[0] != '-' ) {
            dbg() << "Opening file : " << args.at(i) << endl;
            v = YSession::self()->createBufferAndView( args.at(i) );
            if ( !first) {
                first = v;
            }
        } else {
            dbg() << "Parsing option : " << args.at(i) << endl;
            s = args.at(i);

            // --level and --area-level are parsed in YDebugBackend, Ignore them here
            if (s.startsWith("--level") || s.startsWith("--area-level") ) ;

            // Asking for Help
            else if (s == "-h" || s == "--help") {
                showCmdLineHelp( args[0] );
                exit(0);
            }

            // Asking for Version Information
            else if (s == "-v" || s == "--version") {
                showCmdLineVersion();
                exit(0);
            }

            // Passing Keys after the event loop started
            else if (s == "-c") {
                // no splash screen when executing scripts
                YSession::self()->getOptions()->setGroup("Global");
                YSession::self()->getOptions()->getOption("blocksplash")->setBoolean( false );

                if (s.length() > 2) mInitkeys = args[i].mid(2);
                else if (i < args.count() - 1) mInitkeys = args[++i];

                dbg().SPrintf("Init keys = '%s'", qp(mInitkeys) );
            }

            // Load a LUA script from a file
            else if (s == "-s") {
                // no splash screen when executing scripts
                YSession::self()->getOptions()->setGroup("Global");
                YSession::self()->getOptions()->getOption("blocksplash")->setBoolean( false );

                QString luaScript;
                if (s.length() > 2) mLuaScript = args[i].mid(2);
                else if (i < args.count() - 1) mLuaScript = args[++i];

            }

            // Everything else gets an unknown option
            else {
                showCmdLineUnknowOption( args[i] );
                exit( -1);
            }
        }
    }

    if ( !first ) {
        /* no view opened */
        first = YSession::self()->createBufferAndView();
        first->myBuffer()->openNewFile();
        first->displayIntro();
    }

    YSession::self()->setCurrentView( first );
}

00241 void YSession::frontendGuiReady()
{
    dbg() << "frontendGuiReady()" << endl;
    sendInitkeys();
    if (mLuaScript.length()) { 
        runLuaScript();
    }
}

00250 void YSession::runLuaScript()
{
    if (mLuaScript.length() == 0) return;

    dbg() << "runLuaScript(): Running lua script '" << mLuaScript << "'" << endl;

    QString retValue = YLuaEngine::self()->source(mLuaScript);
    dbg().SPrintf( "runLuaScript(): Return Value='%s'", qp(retValue) );
    bool ok;
    int retInt = retValue.toInt(&ok, 0);
    if (ok == false) {
        err().SPrintf("runLuaScript(): Could not convert script return value '%s' to int: ", qp(retValue));
        exit( -2);
    } else {
        exit(retInt);
    }
}

00268 void YSession::sendInitkeys()
{
    dbg() << HERE() << endl;
    dbg() << toString() << endl;
    dbg() << "Init keys to send: '" << mInitkeys << "'" << endl;
    if (mInitkeys.length()) {
        YSession::self()->scriptSendMultipleKeys( mInitkeys );
    }
}


00279 QString YSession::toString() const
{
    QString s;
    s += "Session Content: \n";
    s += "- Buffer list: \n";
    foreach( YBuffer * b, mBufferList ) {
        s += "  + " + b->toString() + '\n';
    }
    s += "- View list: \n";
    foreach( YView * v, mViewList ) {
        s += "  + " + v->toString() + '\n';
    }
    return s;
}

00294 YSession::~YSession()
{
    dbg() << "~YSession" << endl;
    mYzisinfo->write(); // save yzisinfo
    endModes();
    delete YzisHlManager::self();
    delete mSchemaManager;
    delete mSearch;
    delete events;
    delete mRegisters;
    delete mOptions;
    delete mYzisinfo;
    delete YZMapping::self();
    delete YLuaEngine::self();
    delete mTagStack;
    delete mResourceMgr;
}

void YSession::initModes()
{
    mModes[ YMode::ModeIntro ] = new YModeIntro();
    mModes[ YMode::ModeCommand ] = new YModeCommand();
    mModes[ YMode::ModeEx ] = new YModeEx();
    mModes[ YMode::ModeInsert ] = new YModeInsert();
    mModes[ YMode::ModeReplace ] = new YModeReplace();
    mModes[ YMode::ModeVisual ] = new YModeVisual();
    mModes[ YMode::ModeVisualLine ] = new YModeVisualLine();
    mModes[ YMode::ModeVisualBlock ] = new YModeVisualBlock();
    mModes[ YMode::ModeSearch ] = new YModeSearch();
    mModes[ YMode::ModeSearchBackward ] = new YModeSearchBackward();
    mModes[ YMode::ModeCompletion ] = new YModeCompletion();
    YModeMap::Iterator it;
    // XXX orzel : why isn't that done in YMode ctor or YMode* ctors ?
    for ( it = mModes.begin(); it != mModes.end(); ++it )
        it.value()->init();
}
void YSession::endModes()
{
    YModeMap::Iterator it;
    for ( it = mModes.begin(); it != mModes.end(); ++it )
        delete it.value();
    mModes.clear();
}
00337 YModeMap YSession::getModes() const
{
    return mModes;
}
00341 YModeEx* YSession::getExPool()
{
    return (YModeEx*)mModes[ YMode::ModeEx ];
}
00345 YModeCommand* YSession::getCommandPool()
{
    return (YModeCommand*)mModes[ YMode::ModeCommand ];
}

00350 YInfo * YSession::getYzisinfo()
{
    return mYzisinfo;
}

// ================================================================
//
//                          Buffer stuff
//
// ================================================================

00361 YBuffer *YSession::createBuffer( const QString &filename )
{
    dbg().SPrintf("createBuffer( filename='%s' )", qp(filename) );
    //make sure we don't have a buffer of this path yet
    YBuffer *buffer = findBuffer( filename );
    if (buffer) { //already open !
        return buffer;
    }

    buffer = new YBuffer();
    buffer->setState( YBuffer::BufferActive );

    if ( !filename.isEmpty() ) {
        buffer->load( filename );
    } else {
        buffer->openNewFile();
    }

    mBufferList.push_back( buffer );
    guiCreateBuffer( buffer );

    return buffer;
}

00385 YView *YSession::createBufferAndView( const QString& path )
{
    dbg().SPrintf("createBufferAndView( path='%s' )", qp(path) );
    QString filename = YBuffer::parseFilename(path);
    YBuffer *buffer = findBuffer( filename );
    bool alreadyopen = true;
    if (!buffer) {
        alreadyopen = false;
        buffer = createBuffer( filename );
    }

    YView *view;
    if (!alreadyopen) {
        view = createView( buffer );
    } else {
        view = findViewByBuffer(buffer);
    }
    setCurrentView( view );
        buffer->checkRecover();

    view->applyStartPosition( YBuffer::getStartPosition(path) );

    return view;
}

00410 void YSession::removeBuffer( YBuffer *b )
{
    dbg() << "removeBuffer( " << b->toString() << " )" << endl;
    foreach ( YView *v, b->views() ) {
        deleteView( v );
    }
}

00418 void YSession::deleteBuffer( YBuffer *b )
{
    dbg() << "deleteBuffer( " << b->toString() << " )" << endl;
    if ( mBufferList.indexOf( b ) >= 0 ) {
        mBufferList.removeAll( b );
        guiRemoveBuffer( b );
        delete b;
    }

    if ( mBufferList.empty() ) {
        exitRequest();
    }
}

00432 YBuffer* YSession::findBuffer( const QString& path )
{
    QFileInfo fi (path);
    foreach( YBuffer *b, mBufferList )
    if ( b->fileName() == fi.absoluteFilePath())
        return b;
    return NULL; //not found
}

00441 bool YSession::isOneBufferModified() const
{
    foreach( YBuffer * b, mBufferList ) {
        if (b->fileIsModified() ) return true;
    }
    return false;
}

// ================================================================
//
//                          View stuff
//
// ================================================================
00454 YView *YSession::createView( YBuffer *buffer )
{
    dbg().SPrintf("createView( %s )", qp(buffer->toString()) );
    YView *view = guiCreateView( buffer );
    mViewList.push_back( view );

    /* The view must poll the initial information. The reason is
     * that the buffer and the mode had been initialized before the view.
     */
    view->updateFileName();
    view->updateFileInfo();
    view->updateMode();
    view->updateCursor();

    return view;
}

00471 void YSession::deleteView( YView* view )
{
    dbg().SPrintf("deleteView( %s )", qp(view->toString()) );
    if ( !mViewList.contains(view) ) {
        ftl() << "deleteView(): trying to remove an unknown view " << view->getId() << endl;
        return ;
    }

    // Guardian, if we're deleting the last view, close the app
    if ( mViewList.size() == 1 ) {
        dbg() << "deleteView(): last view being deleted, exiting!" << endl;
        exitRequest( 0 );
        return ;
    }

    // if we're deleting the current view, then we have to switch views
    if ( view == currentView() ) {
        setCurrentView( prevView() );
    }

    // remove it
    mViewList.removeAll( view );
    guiDeleteView( view );
}

00496 void YSession::setCurrentView( YView* view )
{
    dbg() << "setCurrentView( " << view->toString() << " )" << endl;
    if (view == currentView()) {
        dbg() << "setCurrentView(): view already set. Returning. " << endl;
        return;
    }
    guiChangeCurrentView( view );
    view->guiSetFocusMainWindow();

    mCurView = view;
    mCurBuffer = view->myBuffer();
}

00510 const YViewList YSession::getAllViews() const
{
    YViewList result;

    for ( YBufferList::const_iterator itr = mBufferList.begin(); itr != mBufferList.end(); ++itr ) {
        YBuffer *buf = *itr;
        const YViewList views = buf->views();

        for ( YViewList::const_iterator vitr = views.begin(); vitr != views.end(); ++vitr ) {
            result.push_back( *vitr );
        }
    }

    return result;
}

00526 YView* YSession::findViewByBuffer( const YBuffer *buffer )
{
    if (buffer == NULL) return NULL;
    foreach( YView *view, mViewList )
    if ( view->myBuffer() == buffer )
        return view;
    return NULL;
}

00535 YView* YSession::firstView()
{
    return mViewList.front();
}

00540 YView* YSession::lastView()
{
    return mViewList.back();
}

00545 YView* YSession::prevView()
{
    if (mViewList.isEmpty()) {
        ftl() << "prevView(): WOW, no view in the list!" << endl;
        return NULL;
    }

    if ( currentView() == NULL ) {
        err() << "prevView(): WOW, current view is NULL !" << endl;
        // if that's null, the previous view is the last view
        return mViewList.last();
    }

    int idx = mViewList.indexOf( currentView() );
    if ( idx == -1 ) {
        ftl() << "prevView(): WOW, current view is not in mViewList !" << endl;
        return NULL;
    }

    if ( idx == 0 )
        idx = mViewList.size();
    return mViewList.value( idx - 1 );
}

00569 YView* YSession::nextView()
{
    if (mViewList.isEmpty()) {
        ftl() << "nextView(): WOW, no view in the list!" << endl;
        return NULL;
    }

    if ( currentView() == NULL ) {
        err() << "nextView(): WOW, current view is NULL !" << endl;
        // if that's null, the previous view is the last view
        return mViewList.first();
    }

    int idx = mViewList.indexOf( currentView() );
    if ( idx == -1 ) {
        ftl() << "nextView(): WOW, current view is not in mViewList !" << endl;
        return NULL;
    }
    return mViewList.value( (idx + 1) % mViewList.size() );
}

// ================================================================
//
//                          Application Termination
//
// ================================================================

00596 bool YSession::exitRequest( int errorCode )
{
    dbg() << "exitRequest( " << errorCode << " ) " << endl;
    //prompt unsaved files XXX
    foreach( YBuffer *b, mBufferList )
    b->saveYzisInfo( b->firstView() );
    /*
    mBuffers.clear();

    getYzisinfo()->updateStartPosition( 
                     mCurBuffer->fileName(),
                     (currentView())->getCursor());
                                          
    getYzisinfo()->writeYzisinfo();*/

    return guiQuit( errorCode );
}


00615 void YSession::saveBufferExit()
{
    dbg() << HERE() << endl;
    if ( saveAll() )
        guiQuit();
}

00622 bool YSession::saveAll()
{
    dbg() << HERE() << endl;
    bool savedAll = true;
    foreach( YBuffer *b, mBufferList )
    if ( !b->fileIsNew() )
        if ( b->fileIsModified() && !b->save() )
            savedAll = false;
    return savedAll;
}

00633 void YSession::scriptSendMultipleKeys ( const QString& text)
{
    dbg() << "scriptSendMultipleKeys(" << text << ")" << endl;
    YKeySequence inputs(text);
    YKeySequence::const_iterator parsePos = inputs.begin();

    sendMultipleKeys( currentView(),  inputs, parsePos);
    QCoreApplication::instance()->processEvents();
    /* }*/
}

00644 CmdState YSession::sendMultipleKeys( YView * view, YKeySequence & inputs, YKeySequence::const_iterator &parsePos)
{
    CmdState state = CmdOk;
    dbg() << "sendMultipleKeys(" << view << ", keys=" << inputs.toString() << ")" << endl;
    if (view->modePool()->current()->mapMode() & MapCmdline) {
        view->modePool()->change( YMode::ModeCommand );
    }

    for(; parsePos != inputs.end() && state != CmdStopped && state != CmdError; ++parsePos ) {
        if ( view->modePool()->current()->mapMode() & MapCmdline ) {
            if ( *parsePos == YKey::Key_Esc
                 || *parsePos == YKey::Key_Enter
                 || *parsePos == YKey::Key_Up
                 || *parsePos == YKey::Key_Down ) {
                state = sendKey( view, *parsePos );
                continue;
            }
            else {
                view->guiSetCommandLineText( view->guiGetCommandLineText() + parsePos->toString() );
                continue;
            }
            
        }
        state = sendKey( view, *parsePos );
    }
    return state;
}

00672 CmdState YSession::sendKey( YView * view, YKey _key)
{
    dbg() << "sendKey( " << view << ", key=" << _key.toString() << ")" << endl;
    CmdState state;

    // Don't respond to pure modifier keys
    if ( _key.key() == YKey::Key_Shift || _key.key() == YKey::Key_Ctrl 
         || _key.key() == YKey::Key_Alt )
        return CmdOk;

    QList<QChar> reg = view->registersRecorded();
    if ( reg.count() > 0 ) {
        for ( int ab = 0 ; ab < reg.size(); ++ab ) {
            QString newReg = _key.toString();
            QStringList curReg = getRegister( reg.at(ab) );
            if ( curReg.size() > 0 )
                newReg.prepend( curReg[ 0 ] );
            setRegister( reg.at(ab), QStringList( newReg ) );
        }
    }

    /** rightleft mapping **/
    bool rightleft = view->getLocalBooleanOption( "rightleft" );
    if ( rightleft && ( view->modePool()->current()->mapMode() & (MapVisual | MapNormal) ) ) {
#define SWITCH_KEY( a, b ) \
    if ( _key == a ) _key.setKey( b );        \
    else if ( _key == b ) _key.setKey( a );
    SWITCH_KEY( YKey::Key_Right, YKey::Key_Left );
    SWITCH_KEY( YKey::Key_H, YKey::Key_L );
    }

//    if ( modifiers.contains ("<SHIFT>")) { //useful?
//        key = key.toUpper();
//        modifiers.remove( "<SHIFT>" );
//    }

//    view->appendInputBuffer( modifiers + key );
    view->setPaintAutoCommit( false );
    state = view->modePool()->sendKey( _key );
    view->commitPaintEvent();

    return state;
}

void YSession::registerModifier ( const QString& mod )
{
    foreach( YView *view, mViewList )
    view->registerModifierKeys( mod );
}

void YSession::unregisterModifier ( const QString& mod )
{
    foreach( YView *view, mViewList )
    view->unregisterModifierKeys( mod );
}

void YSession::saveJumpPosition()
{
    mYzisinfo->updateJumpList( mCurBuffer, currentView()->getCursor());
}

void YSession::saveJumpPosition( const QPoint cursor )
{
    mYzisinfo->updateJumpList( mCurBuffer, cursor );
}

const YCursor YSession::previousJumpPosition()
{
    return mYzisinfo->previousJumpPosition();
}

YTagStack &YSession::getTagStack()
{
    return *mTagStack;
}

00748 int YSession::getIntegerOption( const QString& option )
{
    return YSession::self()->getOptions()->readIntegerOption( option );
}

00753 bool YSession::getBooleanOption( const QString& option )
{
    return YSession::self()->getOptions()->readBooleanOption( option );
}

00758 QString YSession::getStringOption( const QString& option )
{
    return YSession::self()->getOptions()->readStringOption( option );
}

00763 QStringList YSession::getListOption( const QString& option )
{
    return YSession::self()->getOptions()->readListOption( option );
}

00768 void YSession::eventConnect( const QString& event, const QString& function )
{
    events->connect( event, function );
}

00773 QStringList YSession::eventCall( const QString& event, YView *view /*=NULL*/ )
{
    return events->exec( event, view );
}

00778 YInternalOptionPool *YSession::getOptions()
{
    return mOptions;
}

00783 void YSession::setRegister( QChar r, const QStringList& value )
{
    mRegisters->setRegister( r, value );
}

00788 QStringList& YSession::getRegister ( QChar r )
{
    return mRegisters->getRegister( r );
}

00793 QList<QChar> YSession::getRegisters() const
{
    return mRegisters->keys();
}

00798 void * YSession::operator new( size_t tSize )
{
    dbg() << "YSession::new()" << tSize << endl;
    return yzmalloc( tSize );
}

00804 void YSession::operator delete( void *p )
{
    dbg().SPrintf("YSession::delete( %p )", p );
    yzfree(p);
}

// ================================================================
//
//                          Command line stuff
//
// ================================================================

/** Show help text for -h and --help option */
00817 void YSession::showCmdLineHelp( const QString & progName )
{
    QString usage = QString(
                        "%1 [options] [file1 [file2] ... ]\n"
                        "-h | --help : show this message\n"
                        "-v | --version: version information\n"
                        "-c <some key presses> : execute immediately the key presses when yzis starts, asif they were typed by the user.\n"
                    ).arg(progName);
    fputs(qp(usage), stderr);
}

/** Show version text for -v and --version option */
00829 void YSession::showCmdLineVersion()
{
    QString versionText = version();
    fputs(qp(versionText), stderr);
}

00835 QString YSession::version()
{
    return QString( "Yzis - http://www.yzis.org\n" VERSION_CHAR_LONG " " VERSION_CHAR_DATE );
}

/** Show error message for unknown option */
00841 void YSession::showCmdLineUnknowOption( const QString & opt )
{
    fprintf(stderr, "Unrecognised option: %s", qp(opt) );
    dbg().SPrintf("Unrecognised option: %s", qp(opt) );
}


Generated by  Doxygen 1.6.0   Back to index