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