@@ -749,6 +749,147 @@ def command_shell(session_name, window_name, socket_name, socket_path, command):
749749 tmuxp_breakpoint ()
750750
751751
752+ @cli .command (name = 'shell_plus' )
753+ @click .argument ('session_name' , nargs = 1 , required = False )
754+ @click .argument ('window_name' , nargs = 1 , required = False )
755+ @click .option ('-S' , 'socket_path' , help = 'pass-through for tmux -S' )
756+ @click .option ('-L' , 'socket_name' , help = 'pass-through for tmux -L' )
757+ @click .option (
758+ '-c' ,
759+ 'command' ,
760+ help = 'Instead of opening shell, execute python code in libtmux and exit' ,
761+ )
762+ @click .option (
763+ '--use-pythonrc/--no-startup' ,
764+ 'use_pythonrc' ,
765+ help = 'Load the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.' ,
766+ default = False ,
767+ )
768+ def command_shell_plus (
769+ session_name ,
770+ window_name ,
771+ socket_name ,
772+ socket_path ,
773+ command ,
774+ use_pythonrc ,
775+ ):
776+ """shell w/ tab completion.
777+
778+ Credits: django-extensions shell_plus.py 51fef74 (MIT License)
779+ """
780+ server = Server (socket_name = socket_name , socket_path = socket_path )
781+
782+ current_pane = None
783+ if os .getenv ('TMUX_PANE' ) is not None :
784+ try :
785+ current_pane = [
786+ p
787+ for p in server ._list_panes ()
788+ if p .get ('pane_id' ) == os .getenv ('TMUX_PANE' )
789+ ][0 ]
790+ except IndexError :
791+ pass
792+
793+ try :
794+ if session_name :
795+ session = server .find_where ({'session_name' : session_name })
796+ elif current_pane is not None :
797+ session = server .find_where ({'session_id' : current_pane ['session_id' ]})
798+ else :
799+ session = server .list_sessions ()[0 ]
800+
801+ if not session :
802+ raise exc .TmuxpException ('Session not found: %s' % session_name )
803+ except exc .TmuxpException as e :
804+ print (e )
805+ return
806+
807+ try :
808+ if window_name :
809+ window = session .find_where ({'window_name' : window_name })
810+ if not window :
811+ raise exc .TmuxpException ('Window not found: %s' % window_name )
812+ elif current_pane is not None :
813+ window = session .find_where ({'window_id' : current_pane ['window_id' ]})
814+ else :
815+ window = session .list_windows ()[0 ]
816+
817+ except exc .TmuxpException as e :
818+ print (e )
819+ return
820+
821+ try :
822+ if current_pane is not None :
823+ pane = window .find_where ({'pane_id' : current_pane ['pane_id' ]}) # NOQA: F841
824+ else :
825+ pane = window .attached_pane # NOQA: F841
826+ except exc .TmuxpException as e :
827+ print (e )
828+ return
829+
830+ if command is not None :
831+ exec (command )
832+ else :
833+ # Using normal Python shell
834+ import code
835+
836+ import libtmux
837+
838+ imported_objects = {
839+ 'libtmux' : libtmux ,
840+ 'Server' : libtmux .Server ,
841+ 'Session' : libtmux .Session ,
842+ 'Window' : libtmux .Window ,
843+ 'Pane' : libtmux .Pane ,
844+ 'server' : server ,
845+ 'session' : session ,
846+ 'window' : window ,
847+ 'pane' : pane ,
848+ }
849+
850+ try :
851+ # Try activating rlcompleter, because it's handy.
852+ import readline
853+ except ImportError :
854+ pass
855+ else :
856+ # We don't have to wrap the following import in a 'try', because
857+ # we already know 'readline' was imported successfully.
858+ import rlcompleter
859+
860+ readline .set_completer (rlcompleter .Completer (imported_objects ).complete )
861+ # Enable tab completion on systems using libedit (e.g. macOS).
862+ # These lines are copied from Lib/site.py on Python 3.4.
863+ readline_doc = getattr (readline , '__doc__' , '' )
864+ if readline_doc is not None and 'libedit' in readline_doc :
865+ readline .parse_and_bind ("bind ^I rl_complete" )
866+ else :
867+ readline .parse_and_bind ("tab:complete" )
868+
869+ # We want to honor both $PYTHONSTARTUP and .pythonrc.py, so follow system
870+ # conventions and get $PYTHONSTARTUP first then .pythonrc.py.
871+ if use_pythonrc :
872+ for pythonrc in set (
873+ [os .environ .get ("PYTHONSTARTUP" ), os .path .expanduser ('~/.pythonrc.py' )]
874+ ):
875+ if not pythonrc :
876+ continue
877+ if not os .path .isfile (pythonrc ):
878+ continue
879+ with open (pythonrc ) as handle :
880+ pythonrc_code = handle .read ()
881+ # Match the behavior of the cpython shell where an error in
882+ # PYTHONSTARTUP prints an exception and continues.
883+ try :
884+ exec (compile (pythonrc_code , pythonrc , 'exec' ), imported_objects )
885+ except Exception :
886+ import traceback
887+
888+ traceback .print_exc ()
889+
890+ code .interact (local = imported_objects )
891+
892+
752893@cli .command (name = 'freeze' )
753894@click .argument ('session_name' , nargs = 1 , required = False )
754895@click .option ('-S' , 'socket_path' , help = 'pass-through for tmux -S' )
0 commit comments