├── .gitignore ├── LICENSE ├── README.md ├── autoload ├── __init__.py ├── vim_shell_executor.py └── vim_shell_executor.vim ├── doc └── vim-shell-executor.txt ├── plugin └── vim_shell_executor.vim └── tests ├── __init__.py └── vim_shell_executor_tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | tags 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jarrod Taylor 4 | 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-shell-executor 2 | 3 | A simple way to execute Vim buffer contents with a shell command and view the results in a split window. 4 | 5 | I find this most useful for SQL queries however, this will work with any program that can be called from the shell. 6 | 7 | ## The Plugin In Action 8 | 9 | ![executor_demo](https://f.cloud.github.com/assets/4416952/1560433/ec064cf4-5005-11e3-81ea-c1b7fb477915.gif) 10 | 11 | ## How It Works 12 | 13 | The plugin provides two commands: 14 | ``` 15 | ExecuteBuffer 16 | ExecuteSelction 17 | ``` 18 | These commands allow you to execute either the entire buffer or the visually selected region. The first line 19 | passed to the plugin is the shell command that will be used to run the remaing lines of code. For example, 20 | to run a mysql query, the first line connects to the database and the remaining lines are the query being executed. 21 | 22 | The example shown in the .gif above: 23 | ``` shell 24 | mysql -t -u root example 25 | select * from mysql_example_table; 26 | ``` 27 | 28 | ## Installation 29 | 30 | Use your plugin manager of choice. 31 | 32 | - [Pathogen](https://github.com/tpope/vim-pathogen) 33 | - `git clone https://github.com/JarrodCTaylor/vim-shell-executor ~/.vim/bundle/vim-shell-executor` 34 | - [Vundle](https://github.com/gmarik/vundle) 35 | - Add `Plugin 'https://github.com/JarrodCTaylor/vim-shell-executor'` to .vimrc 36 | - Run `:PluginInstall` 37 | - [NeoBundle](https://github.com/Shougo/neobundle.vim) 38 | - Add `NeoBundle 'https://github.com/JarrodCTaylor/vim-shell-executor'` to .vimrc 39 | - Run `:NeoBundleInstall` 40 | - [vim-plug](https://github.com/junegunn/vim-plug) 41 | - Add `Plug 'https://github.com/JarrodCTaylor/vim-shell-executor'` to .vimrc 42 | - Run `:PlugInstall` 43 | -------------------------------------------------------------------------------- /autoload/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JarrodCTaylor/vim-shell-executor/83901ecbee8821f7d9e07e0d8504de363bef0feb/autoload/__init__.py -------------------------------------------------------------------------------- /autoload/vim_shell_executor.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | 4 | INPUT_FILE = "/tmp/input" 5 | ERROR_LOG = "/tmp/error.log" 6 | RESULTS_FILE = "/tmp/results" 7 | 8 | def get_command_from_first_line(line): 9 | if line.startswith("#!"): 10 | return line[2:] 11 | return line 12 | 13 | def get_program_output_from_buffer_contents(buffer_contents): 14 | write_buffer_contents_to_file(INPUT_FILE, buffer_contents[1:]) 15 | command = get_command_from_first_line(buffer_contents[0]) 16 | execute_file_with_specified_shell_program(command) 17 | errors = read_file_lines(ERROR_LOG) 18 | std_out = read_file_lines(RESULTS_FILE) 19 | new_buf = errors + std_out 20 | return new_buf 21 | 22 | 23 | def write_buffer_contents_to_file(file_name, contents): 24 | with open(file_name, "w") as f: 25 | for line in contents: 26 | f.write(line + "\n") 27 | 28 | 29 | def execute_file_with_specified_shell_program(shell_command): 30 | try: 31 | subprocess.check_call("{0} {1} {2} > {3} 2> {4}".format( 32 | shell_command, 33 | redirect_or_arg(shell_command), 34 | INPUT_FILE, 35 | RESULTS_FILE, 36 | ERROR_LOG), 37 | shell=True 38 | ) 39 | except: 40 | pass 41 | 42 | 43 | def redirect_or_arg(shell_command): 44 | redirect_or_agr = "<" 45 | if shell_command == "coffee": 46 | redirect_or_agr = "" 47 | return redirect_or_agr 48 | 49 | 50 | def read_file_lines(file_to_read): 51 | if os.path.isfile(file_to_read): 52 | with open(file_to_read, "r") as f: 53 | return [l.rstrip('\n') for l in f.readlines()] 54 | -------------------------------------------------------------------------------- /autoload/vim_shell_executor.vim: -------------------------------------------------------------------------------- 1 | " -------------------------------- 2 | " Add our plugin to the path 3 | " -------------------------------- 4 | if has("python3") 5 | command! -nargs=1 Py py3 6 | else 7 | command! -nargs=1 Py py 8 | endif 9 | Py import sys 10 | Py import vim 11 | Py sys.path.append(vim.eval('expand(":h")')) 12 | 13 | " -------------------------------- 14 | " Function(s) 15 | " -------------------------------- 16 | function! LeftPad(s,amt,...) 17 | if a:0 > 0 18 | let char = a:1 19 | else 20 | let char = ' ' 21 | endif 22 | return repeat(char,a:amt - len(a:s)) . a:s 23 | endfunction 24 | 25 | function! DisplayTimeDifference(time1,time2) 26 | let l:t1List = split( a:time1, ":" ) 27 | let l:t2List = split( a:time2, ":" ) 28 | let l:difference = abs((l:t1List[1] * 60 + l:t1List[2]) - (l:t2List[1] * 60 + l:t2List[2])) 29 | let l:minutesDifference = LeftPad(float2nr(floor(difference/60)), 2, "0") 30 | let l:secondsDifference = LeftPad(l:difference - (l:minutesDifference * 60), 2, "0") 31 | set cmdheight=2 32 | echo "Execution started at: " . a:time1 . " Successfully finished at: " . a:time2 . " Duration: 00:" . l:minutesDifference . ":" . l:secondsDifference 33 | set cmdheight=1 34 | endfunction 35 | 36 | function! vim_shell_executor#ExecuteWithShellProgram(selection_or_buffer) 37 | let startExecutionTime = strftime("%T") 38 | echo "Execution started at: " . startExecutionTime 39 | Py << endPython 40 | from vim_shell_executor import * 41 | 42 | def create_new_buffer(contents): 43 | vim.command('normal! Hmx``') 44 | delete_old_output_if_exists() 45 | if int(vim.eval('exists("g:executor_output_win_height")')): 46 | vim.command('aboveleft {}split executor_output'.format(vim.eval("g:executor_output_win_height"))) 47 | else: 48 | vim.command('aboveleft split executor_output') 49 | vim.command('normal! ggdG') 50 | vim.command('setlocal filetype=text') 51 | vim.command('setlocal buftype=nowrite') 52 | try: 53 | vim.command('call append(0, {0})'.format(contents)) 54 | except: 55 | for index, line in enumerate(contents): 56 | vim.current.buffer.append(line) 57 | vim.command('execute \'wincmd j\'') 58 | vim.command('normal! `xzt``') 59 | 60 | def delete_old_output_if_exists(): 61 | if int(vim.eval('buflisted("executor_output")')): 62 | capture_buffer_height_if_visible() 63 | vim.command('bdelete executor_output') 64 | 65 | def capture_buffer_height_if_visible(): 66 | executor_output_winnr = int(vim.eval('bufwinnr(bufname("executor_output"))')) 67 | if executor_output_winnr > 0: 68 | executor_output_winheight = vim.eval('winheight("{}")'.format(executor_output_winnr)) 69 | vim.command("let g:executor_output_win_height = {}".format(executor_output_winheight)) 70 | 71 | def get_visual_selection(): 72 | buf = vim.current.buffer 73 | starting_line_num, col1 = buf.mark('<') 74 | ending_line_num, col2 = buf.mark('>') 75 | return vim.eval('getline({}, {})'.format(starting_line_num, ending_line_num)) 76 | 77 | def get_correct_buffer(buffer_type): 78 | if buffer_type == "buffer": 79 | return vim.current.buffer 80 | elif buffer_type == "selection": 81 | return get_visual_selection() 82 | 83 | def execute(): 84 | buf_type = get_correct_buffer(vim.eval("a:selection_or_buffer")) 85 | shell_program_output = get_program_output_from_buffer_contents(buf_type) 86 | create_new_buffer(shell_program_output) 87 | 88 | execute() 89 | 90 | endPython 91 | 92 | let endExecutionTime = strftime("%T") 93 | call DisplayTimeDifference(startExecutionTime, endExecutionTime) 94 | 95 | endfunction 96 | -------------------------------------------------------------------------------- /doc/vim-shell-executor.txt: -------------------------------------------------------------------------------- 1 | *vim-shell-executor.txt* 2 | 3 | =============================================================================== 4 | CONTENTS *vim-shell-executor* 5 | 6 | 1. Intro ....................................... |vim-shell-executor-intro| 7 | 2. Requirements ......................... |vim-shell-executor-requirements| 8 | 3. Usage ....................................... |vim-shell-executor-usage| 9 | 4. Licence ................................... |vim-shell-executor-licence| 10 | =============================================================================== 11 | 1. Intro *vim-shell-executor-intro* 12 | 13 | A simple way to execute Vim buffer contents with a shell command and view the 14 | results in a split window. 15 | 16 | I find this most useful for SQL queries, however this will work with any program 17 | that can be called from the shell. 18 | 19 | 2. Requirements *vim-shell-executor-requirements* 20 | 21 | No additional requires are needed for this plugin. Only the shell programs you 22 | would like to run. 23 | 24 | 3. Usage *vim-shell-executor-usage* 25 | 26 | The plugin provides two commands. 27 | ` 28 | ExecuteBuffer 29 | ExecuteSelction 30 | ` 31 | These commands allow you to execute either the entire buffer or the visually 32 | selected region. The first line passed to the plugin is the shell command that 33 | will be used to run the remaining lines of code. For example to run a mysql query 34 | the first line would be the information you would enter to connect to the database. 35 | The remaining lines are the query that you would like to execute. For example 36 | to run a mysql query on the example database would could use the following. 37 | ``` shell 38 | mysql -t -u root example 39 | select * from mysql_example_table; 40 | ``` 41 | 42 | 4. Licence *vim-shell-executor-licence* 43 | 44 | The MIT License (MIT) 45 | 46 | Copyright (c) 2013 Jarrod Taylor 47 | 48 | 49 | Permission is hereby granted, free of charge, to any person obtaining a copy 50 | of this software and associated documentation files (the "Software"), to deal 51 | in the Software without restriction, including without limitation the rights 52 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 53 | copies of the Software, and to permit persons to whom the Software is 54 | furnished to do so, subject to the following conditions: 55 | 56 | The above copyright notice and this permission notice shall be included in 57 | all copies or substantial portions of the Software. 58 | 59 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 60 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 61 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 62 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 63 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 64 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 65 | THE SOFTWARE. 66 | 67 | " vim: ft=help" 68 | -------------------------------------------------------------------------------- /plugin/vim_shell_executor.vim: -------------------------------------------------------------------------------- 1 | command! ExecuteBuffer call vim_shell_executor#ExecuteWithShellProgram("buffer") 2 | command! -range ExecuteSelection call vim_shell_executor#ExecuteWithShellProgram("selection") 3 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JarrodCTaylor/vim-shell-executor/83901ecbee8821f7d9e07e0d8504de363bef0feb/tests/__init__.py -------------------------------------------------------------------------------- /tests/vim_shell_executor_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import stat 3 | import unittest 4 | import autoload.vim_shell_executor as sut 5 | 6 | INPUT_FILE = "/tmp/input" 7 | ERROR_LOG = "/tmp/error.log" 8 | RESULTS_FILE = "/tmp/results" 9 | 10 | 11 | class VimShellExecutorTests(unittest.TestCase): 12 | 13 | def tearDown(self): 14 | self.delete_if_present(ERROR_LOG) 15 | self.delete_if_present(INPUT_FILE) 16 | self.delete_if_present(RESULTS_FILE) 17 | 18 | def test_get_program_output_from_buffer_contents_returns_properly_formatted_results_when_given_valid_python_input(self): 19 | buffer_contents = ["python", "name = 'Jarrod'", "", "def hello():", " print('Hello {0}'.format(name))", "", "hello()"] 20 | return_result = sut.get_program_output_from_buffer_contents(buffer_contents) 21 | expected_result = ["Hello Jarrod"] 22 | self.assertEqual(expected_result, return_result) 23 | 24 | def test_get_program_output_from_buffer_contents_returns_expected_error_when_given_invalid_input(self): 25 | buffer_contents = ["not_a_program", "fail = 27"] 26 | expected_error = ['/bin/sh: 1: not_a_program: not found'] 27 | returned_buffer = sut.get_program_output_from_buffer_contents(buffer_contents) 28 | self.assertEqual(expected_error, returned_buffer) 29 | 30 | def test_get_program_output_from_buffer_contents_returns_expected_content_when_error_and_std_out_are_produced(self): 31 | buffer_contents = ["python", "print('This is good')", "raise Exception('This is bad')"] 32 | expected_error = ['Traceback (most recent call last):', ' File "", line 2, in ', 'Exception: This is bad', 'This is good'] 33 | returned_buffer = sut.get_program_output_from_buffer_contents(buffer_contents) 34 | self.assertEqual(expected_error, returned_buffer) 35 | 36 | def test_write_buffer_contents_to_file_writes_correct_contents_to_desired_file(self): 37 | buffer_contents = ["var example = function() {", " console.log('this is an example');", "}"] 38 | sut.write_buffer_contents_to_file(RESULTS_FILE, buffer_contents) 39 | with open(RESULTS_FILE, "r") as f: 40 | self.assertEqual(f.readlines(), [line + "\n" for line in buffer_contents]) 41 | 42 | def test_execute_file_with_specific_shell_program_populates_an_error_file_when_given_invalid_input_for_specified_shell_command(self): 43 | sut.write_buffer_contents_to_file(INPUT_FILE, ["(def name 'Jarrod')", "(println name)"]) 44 | sut.execute_file_with_specified_shell_program('python') 45 | self.assertTrue(os.stat(ERROR_LOG)[stat.ST_SIZE] > 0) 46 | 47 | def read_file_to_string(self, file_to_read): 48 | with open(file_to_read, "r") as f: 49 | return f.readlines() 50 | 51 | def delete_if_present(self, file_name): 52 | if os.path.exists(file_name): 53 | os.remove(file_name) 54 | --------------------------------------------------------------------------------