"--------------- Buffer Registration Interface  
--------------------------------------------------------
"--------------------------------------------------------------------------------------

" Function:
" "RegisterAllValidBuffersForSession()"
" Collect the basenames of all suitable buffers and save them in a file
" that is named after the session-file with a special suffix

" Function:
" "MarkAllNonRegisteredBuffersToBeDeleted()"
" The correpsonding buffer numbers are collected in a list for later deletion

" Function:
" "GetBufferDeletionCommandIfAppropriateAndConcatCommand( concatCommand )"
" I best give a mapping as an example to show how it can be used.
" :map <F8> :call 
MarkAllNonRegisteredBuffersToBeDeleted()<CR>:ls<CR>:<C-R>=GetBufferDeletionCommandIfAppropriateAndConcatCommand("Mks")<CR>
"       - call MarkAllNonRegisteredBuffersToBeDeleted()
"       - :ls
"       - Use this function to get something like this ":bd 28 29 | mks" on
"         the commandline and be able to inspect it
" ... I tryed to simplify it but, I think buffer deletion is not possible
" when pulling the expressions register. 




"--------------- Remote Instance Interaction Interface  
--------------------------------------------------------
"--------------------------------------------------------------------------------------

" Command:
" "TurnOnForeignBufferAutoHandling()"
" This sets the autocommand for the SwapExistsEvent. From then on every attempt 
to
" open an already edited file, will record a remote command, and unless 
interrupted when 
" prompted, will TryToDispatchPendingRemoteCommand()

" Command:
" "TryToDispatchPendingRemoteCommand()"
" Normally done automatically, but can also be done manually with this function

" Command:
" "ReturnToTheSourceServerOfTheLastRemoteCommand()"
" Exactly!


" Command:
" "ShowRegisteredCommand()"
" "ShowBuffersEditedByAnotherSession()"
" "ShowLastRemoteCommandSourceServer()"
" "ShowLastReceivedRemoteCommand()"
" Display information only


" Command:
" "SetRemoteInteractionContext( contextSpecifier )"
" The intention for a context was to clone the quickfix buffer remotely.
" Currently it's not interpreted.


" Command: 
" "SetPendingRemoteCommand(RemoteBuffer,RemoteCommand,Context)"
" Needed only if you want to issue remote commands yourself. 
" RemoteCommand is :executed with "normal " prepended. Notes relating to the
" corresponding manual entry:
"       - The opening angle-bracket of vim-keycodes eg <ESC> must be escpaped 
"\<ESC>"
"       - Mappings will be used. Executed without '!' (If the [!] is given, 
mappings will not be used.) TODO???
"       - (The display isn't updated while ":normal" is busy.) The {cmd} is 
aborted automatically 
"               if not completed, but that does not happen until you do 
something else (press a key, ...)
"       - A ":" command must be completed as well.



"---------------------------------------------------------------------------------------------------------
"--------------- Tools 
----------------------------------------------------------------
"---------------------------------------------------------------------------------------------------------



fun! GetBasenameOfPath( path )
            let s:lastPathSepIdx = strridx( a:path , "/" )
            if s:lastPathSepIdx == -1
                    return a:path
            else
                    return strpart( a:path , s:lastPathSepIdx + 1 )
            endif
endfun


fun! ColorMessageOutput( putItThatWay )
        echohl WarningMsg | echomsg a:putItThatWay | echohl None
endfun

fun! ColorMessageOutputConfirm( putItThatWay )
        echohl WarningMsg | call input( a:putItThatWay ) | echohl None
endfun


"---------------------------------------------------------------------------------------------------------
"--------------- Buffer Registration Impl 
----------------------------------------------------------------
"---------------------------------------------------------------------------------------------------------


" This is appended to 'v:this_session' to form the filename for the registered
" buffers
let s:BufferListFilenameExtension = ".RegisteredBuffers"


if ! exists("g:RegisteredBuffersForSession")
       let g:RegisteredBuffersForSession = []
endif

if ! exists("g:ToBeDeletedBufferKludge")
       " had some problems with deletion. Maybe
       " iteration-list manipulation, or similar. Anyway, this is used to
       " aggregate the buffernumbers to be deleted by ':bd' with one call.
       let g:ToBeDeletedBufferKludge= []
endif


fun! s:OneBuffer_RegisterCurrentBufferForSession()

        " Skipping some buffer types
                let l:AlwaysSkippedBufferTypes = [ "nofile" , "nowrite" , 
"quickfix" , "help" ]
                if strlen( &buftype ) != 0 
                        if index( l:AlwaysSkippedBufferTypes , &buftype ) != -1
                                call ColorMessageOutput( "Skipping buffer-type 
for session : " . expand("%") . " type:" . &buftype )
                                return
                        endif
                endif

        " Skipping readonly buffers
                if &readonly == 1 
                        call ColorMessageOutput( "Skipping readonly buffer for 
session : " . expand("%") )
                        return
                endif

        " Truncating the path so that it is only the filename
                let l:FileNamePartOfBufferPath = GetBasenameOfPath( expand("%") 
)

                if strlen( l:FileNamePartOfBufferPath ) == 0 
                        " can happen: new buffers do not have the type "nofile"
                        call ColorMessageOutput( "Empty Name bufnum:" . 
bufnr("%") )
                        return
                endif

        " Registering
                call add( g:RegisteredBuffersForSession , 
l:FileNamePartOfBufferPath )
endfun
        

fun! s:GetBufferListFileName()
        if strlen( v:this_session ) == 0 
                throw "no session, need a session"
        endif

        return v:this_session . s:BufferListFilenameExtension
endfun




fun! s:WriteBufferListToFile()
        let s:BufferListFileName = s:GetBufferListFileName()

        call writefile( g:RegisteredBuffersForSession , s:BufferListFileName )
endfun


fun! s:ReadBufferListFromFile()

        let s:BufferListFileName = s:GetBufferListFileName()

        if ! filereadable( s:BufferListFileName )
            throw "RegisteredBuffers filename not readable : " . 
s:BufferListFileName 
        endif

        let g:RegisteredBuffersForSession = readfile( s:BufferListFileName )

        echo "Did restore these : " 
        echo g:RegisteredBuffersForSession
endfun




fun! s:InsertThisBufferIntoTheToBeDeletedListIfUnmodified()

        if &modified != 0
            throw "Buffer is modified"
        endif

        call add( g:ToBeDeletedBufferKludge , bufnr("%") )
endfun


fun! s:MarkCurrentBufferToBeDeletedIfNotRegisteredAndUnmodified()

        let s:AlwaysKeptBufferTypes = [ "quickfix" ]
        if strlen( &buftype ) != 0 

                if index( s:AlwaysKeptBufferTypes , &buftype ) != -1

                        call ColorMessageOutput( "Keeping buffer-type : " . 
expand("%") . " type:" . &buftype )
                        return
                endif
        endif

        let s:FileNamePartOfBufferPath = GetBasenameOfPath( expand("%") )

        if strlen( s:FileNamePartOfBufferPath ) == 0 
                " can happen: new buffers do not have the type "nofile"
                " bufnr("%") failed once, 
                call ColorMessageOutput( "Empty Name bufnum:" . expand("%") )
                call s:InsertThisBufferIntoTheToBeDeletedListIfUnmodified()
                return
                " TODO does that work correctly together with exceptions?
                " a return?
        endif

        if index( g:RegisteredBuffersForSession , s:FileNamePartOfBufferPath ) 
== -1
                call ColorMessageOutput( "Unregisterd Buffer bufname:" . 
s:FileNamePartOfBufferPath . " bufnr:" . bufnr("%") )
                call s:InsertThisBufferIntoTheToBeDeletedListIfUnmodified()
        endif
endfun


fun! RegisterAllValidBuffersForSession()

        " Can not be part of ':bufdo' iteration, as they are inaccessible
        call EmptyOutTheAggregationOfBuffersEditedWithinAnotherSession()

        let g:RegisteredBuffersForSession = []

        let l:CurrentBufNum = bufnr("%")
        try
            bufdo call s:OneBuffer_RegisterCurrentBufferForSession()
        finally
            if bufexists( l:CurrentBufNum )
                execute "bu " . l:CurrentBufNum
            else 
                call ColorMessageOutput( "Warning : buffer disappeared while 
registering buffers"
            endif
        endtry

        call s:WriteBufferListToFile()

        echo "Registered these : " 
        echo g:RegisteredBuffersForSession

endfun


fun! MarkAllNonRegisteredBuffersToBeDeleted()

        " Can not be part of ':bufdo' iteration, as they are inaccessible
        call EmptyOutTheAggregationOfBuffersEditedWithinAnotherSession()

        " I don't know why ':bufdo' closes quickfix-window if it is the current 
buffer...
        let l:QuickFixGetsClosedIfCurrentWorkaround = 0
        if &buftype == "quickfix"
                let l:QuickFixGetsClosedIfCurrentWorkaround = 1
                execute 0 . "tabnext"
        endif

        let g:ToBeDeletedBufferKludge = []

        call s:ReadBufferListFromFile()

        let l:CurrentBufNum = bufnr("%")
        try 
            bufdo call 
s:MarkCurrentBufferToBeDeletedIfNotRegisteredAndUnmodified()
        finally
               if l:QuickFixGetsClosedIfCurrentWorkaround == 1 
                        tabl
               else
                        if bufexists( l:CurrentBufNum )
                                execute "bu " . l:CurrentBufNum
                        endif
                endif
        endtry

endfun


" This can be used to get something like ":bd 1 2 3 | mks"  on the commandline
" and inspect it prior to executing
:fun! GetBufferDeletionCommandIfAppropriateAndConcatCommand( concatCommand )

" Causes " E523: Not allowed here: bu 4 " when executed through pulling the
" expression-register
   "call MarkAllNonRegisteredBuffersToBeDeleted()
   "ls

    let l:concat = ""
    if strlen( a:concatCommand ) > 0
        let l:concat = "|" . a:concatCommand
    endif

    if empty( g:ToBeDeletedBufferKludge )
        return a:concatCommand
    else
        let l:BufferNumbersToBeDeleted = join(g:ToBeDeletedBufferKludge," ")
        let g:ToBeDeletedBufferKludge = []
        return "bd " . l:BufferNumbersToBeDeleted . l:concat
    endif

:endfun



"---------------------------------------------------------------------------------------------------------
"--------------- Remote Instance Interaction Impl  
--------------------------------------------------------
"---------------------------------------------------------------------------------------------------------



"---------------
" Command Buffer
"---------------

" Note : 'v:servername' envvar that hold the current instance's servername
" The command's data isjust a list with predefined indizes:
let s:BufferIdx = 0
let s:CommandIdx = 1
let s:ContextIdx = 2
let s:RemoteAcceptorFunName = "AcceptRemoteCommandFromClient"
let s:UnhandledRetval = "unhandled"
let s:HandledRetval = "successfullyHandled"

if ! exists("s:RemoteInteractionCommand")
        let s:RemoteInteractionCommand = []
endif


if ! exists("s:SourceServerOfLastRemoteCommand")
        let s:SourceServerOfLastRemoteCommand = ""
endif

if ! exists("s:LastReceivedRemoteCommand")
        let s:LastReceivedRemoteCommand = ""
endif

if ! exists("s:RemoteInteractionContextSpecifier")
        let s:RemoteInteractionContextSpecifier = ""
endif

if ! exists('s:AggregationOfBuffersEditedWithinAnotherSession') 
    let s:AggregationOfBuffersEditedWithinAnotherSession = {}
endif

" Yet unused, but for future use, clients would set the context with this
" function prior to executing a command that could reveal buffers within
" another session (make, tags, ...)
fun! SetRemoteInteractionContext( contextSpecifier )
        let s:RemoteInteractionContextSpecifier = a:contextSpecifier
endfun

"--------------------------------------------------------------------------------------
" Accept Commands from a client
"--------------------------------------------------------------------------------------

fun! 
{s:RemoteAcceptorFunName}(SourceServer,WantedBuffer,WantedCommand,ContextOfCommand)

        " Check if this session has the requested buffer. 
        let l:RelevantBuffer = bufnr( a:WantedBuffer )
        if l:RelevantBuffer == -1 
                return s:UnhandledRetval
        endif

        " inform
        call ColorMessageOutput( printf( "Accepting a remote command. 
SourceServer(%s) WantedBuffer(%s) WantedCommand(%s) Context(%s)", 
a:SourceServer , a:WantedBuffer , a:WantedCommand , a:Context )

        " record the source server and the command
        let s:SourceServerOfLastRemoteCommand = a:SourceServer
        let s:LastReceivedRemoteCommand = printf( "SourceServer(%s) Buffer(%s) 
Command(%s) Context(%s)" , a:SourceServer , a:WantedBuffer , strtrans( 
a:WantedCommand ) , a:ContextOfCommand )

        " this is an utility to jump to/from the last tab page which is kind of 
a rummaging tab.
        " MAILTODO : remove this. 
        call SetLastTabSwitchTabPageNumber()

        " go to last tab, top left-window , visualize the buffer, and present it
        tabl
        wincmd t
        execute ":buffer " . l:RelevantBuffer
        call foreground()

        " Assert we are in the right buffer
        if bufnr("%") != bufnr( l:RelevantBuffer )
                throw "Assertion of being in the right buffer immediately 
before command execution failed"
        endif

        " do what must be done
        call ColorMessageOutput( "executing '" . strtrans(a:WantedCommand). "'" 
)
        call ColorMessageOutput( "strlen is (want to know if special chars are 
converted) : " . strlen(a:WantedCommand) )

        let v:errormsg = ""

        " As it appears ':normal xyz' executed in insert mode (from remote) 
does not 
        " insert these chars but executes them in normal mode (hey, now I get 
the name, I though it would mean 'unimpressed'). 
        " It seems that you can't even leave insert mode by prepending 
"\<C-\>\<C-N>"
        " Anyway, the former renders the latter unnecessary. 

        " double escape would not hurt, would it? It ensures the command is 
terminated.
        " Necessary for example for the ':ta' swapcommands 

        execute ":normal " . expand(a:WantedCommand) . "\e"

        if strlen( v:errormsg ) != 0
                echo "(TODO: duplicated output of errormsg?)" . v:errormsg
        endif

        return s:HandledRetval
endfun

"--------------------------------------------------------------------------------------
" Server Focus
"--------------------------------------------------------------------------------------

fun! ReturnToTheSourceServerOfTheLastRemoteCommand()

        if strlen(s:SourceServerOfLastRemoteCommand) == 0
                call ColorMessageOutput( "Cannot return, no source server 
recorded" )
                return
        endif

        try
                call remote_expr( s:SourceServerOfLastRemoteCommand , 
"foreground()" )
        catch /E241/
                call ColorMessageOutput( s:SourceServerOfLastRemoteCommand . ": 
no such server. Giving focus to that server failed." )
        endtry
        
endfun

"--------------------------------------------------------------------------------------
" Sending a Command Request
"--------------------------------------------------------------------------------------

fun! GimmeListOfTheServersWithoutCurrentServerAsAnActualList()

        let l:WholeList = split( serverlist() )

        let l:ThisServersIndex = index( l:WholeList , v:servername )
        if ( l:ThisServersIndex == -1 ) 
                throw "serverlist without v:servername - unexpected"
        endif

        call remove( l:WholeList , l:ThisServersIndex )

        if index( l:WholeList , v:servername ) != -1 
                throw "Failed to remove v:servername from serverlist() - 
unexpected, should really work"
        endif

        return l:WholeList
endfun


" TODO ELIGIBLE ELLIGIBLE?
fun! GetPendingRemoteCommandAsAnExpressionEligibleForSending()

        " empty return-string means no command pending.

        if empty( s:RemoteInteractionCommand ) == 1
                return ""
        endif

        if len( s:RemoteInteractionCommand ) != 3
                throw "Invalid len(s:RemoteInteractionCommand) : " . string( 
s:RemoteInteractionCommand )
        endif

        let l:BufferBase = GetBasenameOfPath( s:RemoteInteractionCommand[ 
s:BufferIdx ] )
        let l:RemCommand = s:RemoteInteractionCommand[ s:CommandIdx ] 
        let l:Context = s:RemoteInteractionCommand[ s:ContextIdx ] 
                
        let l:RequestedRemoteCommand = printf( "%s('%s','%s','%s','%s')" , 
s:RemoteAcceptorFunName , v:servername , l:BufferBase , l:RemCommand , 
l:Context )

        return l:RequestedRemoteCommand
                
endfun


fun! SetPendingRemoteCommand(RemoteBuffer,RemoteCommand,Context)
        let s:RemoteInteractionCommand = [ a:RemoteBuffer , a:RemoteCommand , 
a:Context]
endfun


fun! TryToDispatchPendingRemoteCommand()

        let l:RemoteCommandToBeDispatched = 
GetPendingRemoteCommandAsAnExpressionEligibleForSending()

        if strlen( l:RemoteCommandToBeDispatched ) == 0
                call ColorMessageOutput( "No remote command pending" )
                return
        endif

        call ColorMessageOutput( "Trying to dispatch this : " . strtrans( 
l:RemoteCommandToBeDispatched ) )

        let l:HasCommandBeenHandled = ""
        for l:CandidateServer in 
GimmeListOfTheServersWithoutCurrentServerAsAnActualList()
                
                try
                        let l:HasCommandBeenHandled = remote_expr( 
l:CandidateServer , l:RemoteCommandToBeDispatched )

                        if l:HasCommandBeenHandled == s:HandledRetval

                                call ColorMessageOutput( printf( "server(%s) 
accepted the command" , l:CandidateServer ) )
                                break
                        endif

                catch /E241/
                        throw "Impossible? A server from the serverlist() 
disappeared"
                endtry
        endfor

        if l:HasCommandBeenHandled != s:HandledRetval 
                call ColorMessageOutput( "No server accepted the command" )
        endif
        
endfun


"--------------------------------------------------------------------------------------
" SwapExistsEvent handling, and recording/deleting the buffers which are added 
but not loaded
"--------------------------------------------------------------------------------------

fun! EmptyOutTheAggregationOfBuffersEditedWithinAnotherSession()

       for l:BuffernameToDelete in 
keys(s:AggregationOfBuffersEditedWithinAnotherSession)

                let l:ToBeDeletedBufNumber = bufnr( l:BuffernameToDelete )

                if l:ToBeDeletedBufNumber == -1 

                        call ColorMessageOutput( "Buffer does not exist : " . 
l:BuffernameToDelete )
                        continue

                elseif bufloaded( l:ToBeDeletedBufNumber )

                        call ColorMessageOutput( "Buffer is now loaded. keeping 
it : " . l:BuffernameToDelete )

                elseif ! buflisted( l:ToBeDeletedBufNumber )

                        call ColorMessageOutput( "Buffer is now missing - 
unexpected: " . l:BuffernameToDelete )

                else
                        " is not loaded can't be modified, will produce error 
otherwise (no '!' after 'bd')
                        call ColorMessageOutput( "Deleting foreign buffer : " . 
l:BuffernameToDelete )
                        execute( "bd " . l:ToBeDeletedBufNumber )
                endif
       endfor

       let s:AggregationOfBuffersEditedWithinAnotherSession = {}
endfun


fun! HandleSwapExistsEventAndRecordRemoteCommand( BufferBeingEditedAlready )

        let l:BufferBeingEditedAlreadyBasename = GetBasenameOfPath( 
a:BufferBeingEditedAlready )
        
        " Don't know how to prevent the remote buffers from being recorded in 
the 
        " local bufferlist Can't delete them right here (probably sandbox)
        let s:AggregationOfBuffersEditedWithinAnotherSession[ 
BufferBeingEditedAlreadyBasename ] = 0  

        call SetPendingRemoteCommand( BufferBeingEditedAlreadyBasename , 
v:swapcommand , s:RemoteInteractionContextSpecifier )

        " a-bort (alternative would be q-uit). Both add the buffer to the 
bufferlist.
        let v:swapchoice = 'a' 

        call ColorMessageOutputConfirm( printf("Buffer edited by another 
session. Recorded remote command : buffer(%s) command(%s). Going to 
dispatch..." , BufferBeingEditedAlreadyBasename , strtrans(v:swapcommand) ) )

        call TryToDispatchPendingRemoteCommand()
endfun


fun! TurnOnForeignBufferAutoHandling()
        au! SwapExists * call HandleSwapExistsEventAndRecordRemoteCommand( 
expand('<afile>') )
endfun


"--------------------------------------------------------------------------------------
" Info
"--------------------------------------------------------------------------------------

fun! ShowRegisteredCommand()
        echo "Remote Command is (strtrans converted): " . strtrans( 
GetPendingRemoteCommandAsAnExpressionEligibleForSending() ) 
endfun

fun! ShowLastRemoteCommandSourceServer()
        echo "Last Remote Command Source Server is : " . 
s:SourceServerOfLastRemoteCommand
endfun

fun! ShowLastReceivedRemoteCommand()
        echo "Last Received Remote Command is : " . s:LastReceivedRemoteCommand
endfun

fun! ShowBuffersEditedByAnotherSession()
        echo "Buffers edited by another session : " . 
string(keys(s:AggregationOfBuffersEditedWithinAnotherSession))
endfun


--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

Raspunde prin e-mail lui