diff --git a/doc/vimux.txt b/doc/vimux.txt index 37de16a..df6d305 100644 --- a/doc/vimux.txt +++ b/doc/vimux.txt @@ -61,7 +61,10 @@ process finishes and will see the output in the pane when it's finished. Furthermore there are several handy commands all starting with 'Vimux': - |VimuxRunCommand| - - |VimuxRunLastCommand| + - |VimuxSendText| + - |VimuxSendKeys| + - |VimuxOpenPane| + - |VimuxRunLastCommand| - |VimuxCloseRunner| - |VimuxClosePanes| - |VimuxCloseWindows| @@ -70,22 +73,7 @@ Furthermore there are several handy commands all starting with 'Vimux': - |VimuxPromptCommand| - |VimuxClearRunnerHistory| - -Note: -Earlier the all commands had different names. There are still aliases for -convenience. Please chang your configuration according to the new naming -conventions! - -The DEPRECATED commands: - - |PromptVimTmuxCommand| - - |RunLastVimTmuxCommand| - - |InspectVimTmuxRunner| - - |CloseVimTmuxRunner| - - |CloseVimTmuxPanes| - - |InterruptVimTmuxRunner| - ------------------------------------------------------------------------------ - *RunVimTmuxCommand* *VimuxRunCommand* VimuxRunCommand~ @@ -100,7 +88,32 @@ vimux from automatically sending a return after the command. < ------------------------------------------------------------------------------ - *PromptVimTmuxCommand* + *VimuxSendText* +VimuxSendText~ + +Send raw text to the runer pane. This command will not open a new pane if one +does not already exist. You will need to use VimuxOpenPane to do this. This +command can be used to interact with REPLs or other interactive terminal +programs that are not shells. + + +------------------------------------------------------------------------------ + *VimuxSendKeys* +VimuxSendKeys~ + +Send keys to the runner pane. This command will not open a new pane if one +does not already exist. You will need to use VimuxOpenPane to do this. You can +use this command to send keys such as "Enter" or "C-c" to the runner pane. + +------------------------------------------------------------------------------ + *VimuxOpenPane* +VimuxOpenPane~ + +This will either opne a new pane or use the nearest pane and set it as the +vimux runner pane for the other vimux commands. You can control if this command +uses the nearest pane or always creates a new one with g:VimuxUseNearestPane + +------------------------------------------------------------------------------ *VimuxPromptCommand* VimuxPromptCommand~ @@ -112,7 +125,6 @@ pane. < ------------------------------------------------------------------------------ - *RunLastVimTmuxCommand* *VimuxRunLastCommand* VimuxRunLastCommand~ @@ -123,7 +135,6 @@ Run the last command executed by `VimuxRunCommand` < ------------------------------------------------------------------------------ - *InspectVimTmuxRunner* *VimuxInspectRunner* VimuxInspectRunner~ @@ -135,7 +146,6 @@ pmode (scroll mode). < ------------------------------------------------------------------------------ - *CloseVimTmuxRunner* *VimuxCloseRunner* VimuxCloseRunner~ @@ -146,18 +156,6 @@ Close the tmux runner created by `VimuxRunCommand` < ------------------------------------------------------------------------------ - *CloseVimTmuxPanes* - *VimuxClosePanes* -VimuxClosePanes~ - -Close all other tmux panes in the current window. -> - " Close all other tmux panes in current window - map vx :VimuxClosePanes -> - ------------------------------------------------------------------------------- - *InterruptVimTmuxRunner* *VimuxInterruptRunner* VimuxInterruptRunner~ @@ -194,22 +192,19 @@ Full Keybind Example~ map rb :call VimuxRunCommand("clear; rspec " . bufname("%")) " Prompt for a command to run - map rp :VimuxPromptCommand + map vp :VimuxPromptCommand " Run last command executed by VimuxRunCommand - map rl :VimuxRunLastCommand + map vl :VimuxRunLastCommand " Inspect runner pane - map ri :VimuxInspectRunner - - " Close all other tmux panes in current window - map rx :VimuxClosePanes + map vi :VimuxInspectRunner " Close vim tmux runner opened by VimuxRunCommand - map rq :VimuxCloseRunner + map vq :VimuxCloseRunner " Interrupt any command running in the runner pane - map rs :VimuxInterruptRunner + map vx :VimuxInterruptRunner > ------------------------------------------------------------------------------ @@ -220,11 +215,13 @@ Here is how to use vimux to send code to a REPL. This is similar to tslime. First, add some helpful mappings. > - " Prompt for a command to run - map vp :VimuxPromptCommand + function! VimuxSlime() + call VimuxSendText(@v) + call VimuxSendKeys("Enter") + endfunction " If text is selected, save it in the v buffer and send that buffer it to tmux - vmap vs "vy :call VimuxRunCommand(@v . "\n", 0) + vmap vs "vy :call VimuxSlime() " Select current paragraph and send it to tmux nmap vs vipvs diff --git a/plugin/vimux.vim b/plugin/vimux.vim index 1f0163c..6bcdde4 100644 --- a/plugin/vimux.vim +++ b/plugin/vimux.vim @@ -3,16 +3,8 @@ if exists("g:loaded_vimux") || &cp endif let g:loaded_vimux = 1 -if !has("ruby") - finish -end - - -" New style commands with 'normalized' names command VimuxRunLastCommand :call VimuxRunLastCommand() command VimuxCloseRunner :call VimuxCloseRunner() -command VimuxClosePanes :call VimuxClosePanes() -command VimuxCloseWindows :call VimuxCloseWindows() command VimuxInspectRunner :call VimuxInspectRunner() command VimuxScrollUpInspect :call VimuxScrollUpInspect() command VimuxScrollDownInspect :call VimuxScrollDownInspect() @@ -20,341 +12,136 @@ command VimuxInterruptRunner :call VimuxInterruptRunner() command VimuxPromptCommand :call VimuxPromptCommand() command VimuxClearRunnerHistory :call VimuxClearRunnerHistory() -" DEPRECATED -command RunLastVimTmuxCommand :call VimuxRunLastCommand() -command CloseVimTmuxRunner :call VimuxCloseRunner() -command CloseVimTmuxPanes :call VimuxClosePanes() -command CloseVimTmuxWindows :call VimuxCloseWindows() -command InspectVimTmuxRunner :call VimuxInspectRunner() -command InterruptVimTmuxRunner :call VimuxInterruptRunner() -command PromptVimTmuxCommand :call VimuxPromptCommand() +function! VimuxRunLastCommand() + if exists("g:VimuxRunnerPaneIndex") + call VimuxRunCommand(g:VimuxLastCommand) + else + echo "No last vimux command." + endif +endfunction +function! VimuxRunCommand(command, ...) + if !exists("g:VimuxRunnerPaneIndex") || _VimuxHasPane(g:VimuxRunnerPaneIndex) == -1 + call VimuxOpenPane() + endif -" new style functions -function VimuxRunCommand(command, ...) let l:autoreturn = 1 - if exists("a:1") let l:autoreturn = a:1 endif - let s:_VimTmuxCmd = substitute(a:command, '`', '\\`', 'g') - let s:_VimTmuxCmdAutoreturn = l:autoreturn + let resetSequence = _VimuxOption("g:VimuxResetSequence", "q C-u") + let g:VimuxLastCommand = a:command + + call VimuxSendKeys(resetSequence) + call VimuxSendText(a:command) if l:autoreturn == 1 - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd")) - else - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd"), false) + call VimuxSendKeys("Enter") endif endfunction -" deprecated! -function RunVimTmuxCommand(command, ...) - " TODO replace me with the direct function call! - let l:autoreturn = 1 - - if exists("a:1") - let l:autoreturn = a:1 - endif - - let s:_VimTmuxCmd = substitute(a:command, '`', '\\`', 'g') - let s:_VimTmuxCmdAutoreturn = l:autoreturn +function! VimuxSendText(text) + call VimuxSendKeys('"'.escape(a:text, '"').'"') +endfunction - if l:autoreturn == 1 - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd")) +function! VimuxSendKeys(keys) + if exists("g:VimuxRunnerPaneIndex") + call system("tmux send-keys -t ".g:VimuxRunnerPaneIndex." ".a:keys) else - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd"), false) + echo "No vimux runner pane. Create one with VimuxOpenPane" endif endfunction +function! VimuxOpenPane() + let height = _VimuxOption("g:VimuxHeight", 20) + let orientation = _VimuxOption("g:VimuxOrientation", "v") + let nearestIndex = _VimuxNearestPaneIndex() -function VimuxRunLastCommand() - if exists("s:_VimTmuxCmd") - if s:_VimTmuxCmdAutoreturn == 1 - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd")) - else - ruby CurrentTmuxSession.new.run_shell_command(Vim.evaluate("s:_VimTmuxCmd"), false) - endif + if _VimuxOption("g:VimuxUseNearestPane", 1) == 1 && nearestIndex != -1 + let g:VimuxRunnerPaneIndex = nearestIndex else - echo "No last command" + call system("tmux split-window -p ".height." -".orientation) + let g:VimuxRunnerPaneIndex = _VimuxTmuxPaneIndex() + call system("tmux last-pane") endif endfunction -" deprecated! -function RunLastVimTmuxCommand() - call VimuxRunLastCommand() -endfunction - - -function VimuxClearWindow() - if exists("s:_VimTmuxRunnerPane") - unlet s:_VimTmuxRunnerPane - end +function! VimuxCloseRunner() + if exists("g:VimuxRunnerPaneIndex") + call system("tmux kill-pane -t ".g:VimuxRunnerPaneIndex) + unlet g:VimuxRunnerPaneIndex + endif endfunction -" deprecated! -function ClearVimTmuxWindow() - call VimuxClearWindow() +function! VimuxInspectRunner() + call system("tmux select-pane -t ".g:VimuxRunnerPaneIndex) + call system("tmux copy-mode") endfunction - -" deprecated! -function CloseVimTmuxWindows() - call VimuxCloseWindows() +function! VimuxScrollUpInspect() + call VimuxInspectRunner() + call system("tmux last-pane") + call VimuxSendKeys("C-u") endfunction - -function VimuxCloseRunner() - ruby CurrentTmuxSession.new.close_runner_pane - call VimuxClearWindow() +function! VimuxScrollDownInspect() + call VimuxInspectRunner() + call system("tmux last-pane") + call VimuxSendKeys("C-d") endfunction -" deprecated! -function CloseVimTmuxRunner() - call VimuxCloseRunner() +function! VimuxInterruptRunner() + call VimuxSendKeys("^c") endfunction - -function VimuxClosePanes() - ruby CurrentTmuxSession.new.close_other_panes - call VimuxClearWindow() +function! VimuxClearRunnerHistory() + if exists("g:VimuxRunnerPaneIndex") + call system("tmux clear-history -t ".g:VimuxRunnerPaneIndex) + endif endfunction -" deprecated! -function CloseVimTmuxPanes() - call VimuxClosePanes() +function! VimuxPromptCommand() + let l:command = input(_VimuxOption("g:VimuxPromptString", "Command? ")) + call VimuxRunCommand(l:command) endfunction - -function VimuxInterruptRunner() - ruby CurrentTmuxSession.new.interrupt_runner +function! _VimuxTmuxSession() + return _VimuxTmuxProperty("S") endfunction -" deprecated! -function InterruptVimTmuxRunner() - call VimuxInterruptRunner() +function! _VimuxTmuxPaneIndex() + return _VimuxTmuxProperty("P") endfunction -function VimuxScrollDownInspect() - ruby CurrentTmuxSession.new.inspect_scroll_down +function! _VimuxTmuxWindowIndex() + return _VimuxTmuxProperty("I") endfunction -function VimuxScrollUpInspect() - ruby CurrentTmuxSession.new.inspect_scroll_up -endfunction +function! _VimuxNearestPaneIndex() + let panes = split(system("tmux list-panes"), "\n") -function VimuxInspectRunner() - ruby CurrentTmuxSession.new.inspect_runner -endfunction + for i in panes + if match(panes[i], "(active)") == -1 + return split(panes[i], ":")[0] + endif + endfor -" deprecated! -function InspectVimTmuxRunner() - call VimuxInspectRunner() + return -1 endfunction - -function VimuxPromptCommand() - let l:command = input("Command? ") - if exists("g:VimuxPromptString") - let l:command = input(g:VimuxPromptString) +function! _VimuxOption(option, default) + if exists(a:option) + return eval(a:option) + else + return a:default endif - call VimuxRunCommand(l:command) endfunction -" deprecated! -function PromptVimTmuxCommand() - call VimuxPromptCommand() +function! _VimuxTmuxProperty(property) + return substitute(system("tmux display -p '#".a:property."'"), '\n$', '', '') endfunction - -function VimuxClearRunnerHistory() - ruby CurrentTmuxSession.new.clear_runner_history +function! _VimuxHasPane(index) + return match(system("tmux list-panes"), a:index.":") endfunction - -ruby << EOF -class TmuxSession - def initialize(session, window, pane) - @session = session - @window = window - @pane = pane - @runner_pane = vim_cached_runner_pane - end - - def vim_cached_runner_pane - if Vim.evaluate('exists("s:_VimTmuxRunnerPane")') != 0 - Vim.evaluate('s:_VimTmuxRunnerPane') - else - nil - end - end - - def vim_cached_runner_pane=(runner_pane) - Vim.command("let s:_VimTmuxRunnerPane = '#{runner_pane}'") - end - - def clear_vim_cached_runner_pane - Vim.command("unlet s:_VimTmuxRunnerPane") - end - - def clear_runner_history - _run("clear-history -t #{target(:pane => runner_pane)}") - end - - def height - if Vim.evaluate('exists("g:VimuxHeight")') != 0 - Vim.evaluate('g:VimuxHeight') - else - 20 - end - end - - def orientation - if Vim.evaluate('exists("g:VimuxOrientation")') != 0 && ["h", "v"].include?(Vim.evaluate('g:VimuxOrientation')) - "-#{Vim.evaluate('g:VimuxOrientation')}" - else - "-v" - end - end - - def reset_sequence - if Vim.evaluate('exists("g:VimuxResetSequence")') != 0 - "#{Vim.evaluate('g:VimuxResetSequence')}" - else - "q C-u" - end - end - - def inspect_runner - _run("select-pane -t #{target(:pane => runner_pane)}") - _run("copy-mode") - end - - def inspect_send_command(cmd) - t = target(:pane => runner_pane) - _run("select-pane -t #{t}") - _run("copy-mode") - _send_command(cmd, t, false) - _move_up_pane - end - - def inspect_scroll_up - inspect_send_command("C-u") - end - - def inspect_scroll_down - inspect_send_command("C-d") - end - - def current_panes - _run('list-panes').split("\n").map do |line| - line.split(':').first - end - end - - def active_pane_id - _run('list-panes').split("\n").map do |line| - return line.split[-2] if line =~ /\(active\)/ - end - end - - def target(args={}) - "'#{args.fetch(:session, @session)}':'#{args.fetch(:window, @window)}'.#{args.fetch(:pane, @pane)}" - end - - def runner_pane - if @runner_pane.nil? - use_nearest_pane = Vim.evaluate('exists("g:VimuxUseNearestPane")') != 0 - if use_nearest_pane && nearest_inactive_pane_id - _run("select-pane -t #{target(:pane => nearest_inactive_pane_id)}") - else - _run("split-window -p #{height} #{orientation}") - end - @runner_pane = active_pane_id - _send_command("cd #{`pwd`}", target(:pane => runner_pane)) - Vim.command("let s:_VimTmuxRunnerPane = '#{@runner_pane}'") - end - - _run('list-panes').split("\n").map do |line| - return line.split(':').first if line =~ /#{@runner_pane}/ - end - - @runner_pane = nil - runner_pane - end - - def interrupt_runner - _run("send-keys -t #{target(:pane => runner_pane)} ^c") - end - - def run_shell_command(command, auto_return = true) - reset_shell - _send_command(command, target(:pane => runner_pane), auto_return) - _move_up_pane - end - - def close_runner_pane - _run("kill-pane -t #{target(:pane => runner_pane)}") unless @runner_pane.nil? - end - - def close_other_panes - if _run("list-panes").split("\n").length > 1 - _run("kill-pane -a") - end - end - - def reset_shell - _run("send-keys -t #{target(:pane => runner_pane)} #{reset_sequence}") - end - - def nearest_inactive_pane_id - panes = _run("list-pane").split("\n") - pane = panes.find { |p| p !~ /active/ } - pane ? pane.split(':').first : nil - end - - def _move_up_pane - _run("select-pane -t #{target}") - end - - def _send_command(command, target, auto_return = true) - _run("send-keys -t #{target} \"#{_escape_command(command)}\"") - _run("send-keys -t #{target} Enter") if auto_return - end - - def _escape_command(command) - command.gsub('"', '\"').gsub('$', '\$').sub(/;\z/, '\;') - end - - def _run(command) - `tmux #{command}` - end -end - -class CurrentTmuxSession < TmuxSession - def initialize - if tmux? - session = self.get_session - window = self.get_property(:active, :window) - pane = self.get_property(:active, :pane) - - super(session, window, pane) - else - raise "You are not in a tmux session" - end - end - - def get_property(match, type) - _run("list-#{type.to_s}").split("\n").each do |line| - return line.split(':').first if line =~ /\(#{match.to_s}\)/ - end - end - - def get_session - _run("display -p '#S'").strip - end - - def tmux? - `echo $TMUX` =~ /.+/ ? true : false - end -end -EOF