Git Product home page Git Product logo

vim-flow's Introduction

Vim Flow

Declarative build-test-run workflow with Vim.

#.flow.yaml
go: 
  cmd: go run {{filepath}}

image

VimFlow keeps you in your editor and productive allowing you to run, test or format your current project with a single command. By exposing a simple interface and allowing you to define run commands in whatever shell language you are comfortable with, you can easily configure projects and scripts to your liking.

Some common use cases for vim-flow are:

  • running your favorite one off script executor of choice eg: bash|python|ruby|go run etc...
  • running a code formatter / test suite for a large project you are working on
  • running any arbitrary script at any given time from vim while working

Flow Run

The :FlowRun command is responsible for executing anything and everything for a buffer within vim. Behind the scenes, :FlowRun will fetch the current filename and find a .flow.yml file to run. vim-flow starts at the current buffer's directory and walks upwards looking for the first .flow.yml file it finds.

Let's say you are working on main.go and have the following directory structure:

.
├── .flow.yml
└── main.go

and your .flow.yml file contains the following:

# .flow.yml
go: 
  cmd: goimports -w {{filepath}} && go run {{filepath}}

:FlowRun will load in the local .flow.yml, match up and find the script go imports {{filepath}} && go run {{filepath}} by extension (.go) and will run that in the current vim window.

cmd can be any command you can run in your terminal! Behind the scenes, vim-flow templates this out into a temporary file script and runs that script as part of its execution.

Here's a more complicated example:

.
|-- .flow.yml
|-- benchmark_test.go
└── main.go
# .flow.yml
go:
  cmd: | #!/bin/bash
    cd $(dirname {{filepath}})
    set -e
    goimports -w .
    go test -v .
    go test -bench=.
    GOOS=linux GOARCH=386 go build server.go

Behind the scenes, flow would write the entire contents of the cmd out to a temporary script and execute it as a bash script. In this particular example, you could run a formatter, test suite, benchmark suite and a build job all with one vim command.

Flow Lock

Part of the flow workflow is staying in your editor, popping around and changing filepaths frequently. Let's say you are working on a large project with many different files and build jobs:

In this example, you may want to have different flows for the gopackage directory, some bash scripts in /scripts and even the bins/main.go file.

.
├── .flow.yml
├── bins
│   └── main.go
├── gopackage
│   ├── .flow.yml
│   ├── gopackage.go
│   └── gopackage_test.go
└── scripts
    ├── build
    └── test

You may also have an editor open with many of these buffers open. While you are working in gopackage you may want to build the entire project.

vim-flow supports the ability to "lock" onto a file. By running :FlowToggleLock you can lock onto a file and any future calls to :FlowRun will use that file. This allows you to pop around to many different files while still calling the flow that you'd like to.

Let's say we have the following flow, where you want to run go build for any go file and simply want to execute any other file by itself.

default: 
  cmd: {{filepath}}

go: 
  cmd: | #!/bin/bash
    cd $(dirname {{filepath}})
    go build .

By locking onto main.go with :FlowToggleLock in your vim session, whenever you call :FlowRun flow will run the go flow. This allows you to switch to other files, buffers around your work space and still run the flow you'd like.

To unlock a file, simply call :FlowToggleLock again.

Tmux Support

vim-flow supports running commands in a separate tmux session and pane. For longer builds or when you'd like to avoid interrupting your vim session, you can specify this in a flow file:

# .flow.yaml
go:
  tmux_session: foo
  tmux_pane: 1
  cmd: | #!/bin/bash
    echo "executing go script in another tmux pane"
    go run {{filepath}}

tmux example

Installation

vim-flow can be installed by simply adding it as a dependency using vundle:

Plugin 'jonmorehouse/vim-flow'

vim-flow requires python support within vim. If you aren't sure if you have python enabled in your current vim installation, the following command will return 1/0 for success failure.

:echo has('python')

Getting Started

You'll probably want to add some reasonable flow defaults. Its nice to be able to hit :FlowRun from any sort of "standard" one off script and it just work.

Adding a $HOME/.flow.yml file with some reasonable defaults is a good starting point.

# $HOME/

# execute any plain script by itself
default:
  cmd: {{filepath}}


# run flake8 and python {{filepath}} for any python file
py: 
  cmd: |#!/bin/bash
    flake8 {{filepath}}
    python {{filepath}}

# run go fmt and go run {{filepath}} for any golang file
go: 
  cmd: |#!/bin/bash
    go fmt -w {{filepath}}
    go run {{filepath}}

Customization

VimFlow provides two commands out of the box:

  • :FlowRun - run a flow for the current file.
  • :FlowToggleLock - lock or unlock the current file

By design, vim-flow doesn't have any opinions about how these commands should be run as part of your vim workflow. For instance, it might be helpful to map one or both of these commands to normal mode mappings to avoid having to call them from the vim command line each time.

For example, to link <Leader>, to :FlowRun and <Leader>l to :FlowToggleLock you can add the following to your $HOME/.vimrc file:

# $HOME/.vimrc
map <Leader>, :FlowRun<CR>
map <Leader>l :FlowToggleLock<CR>

FAQ

Why use python instead of entirely native vim-script?

It's definitely possible to write the entirety of this plugin in vimscript, but I've found that it s more intuitive to use python. It's a pretty standard vim dependency and allows for testing (coming soon) and a better maintenance/development experience. The vimscript surface area is super minimal and can be found #here.

Why not use foo plugin?

Plugins exist for many different runtimes/languages etc in vim, but attempting to set up Vim for every unique project is tedious and requires many different plugins. With vim-flow you have a common interface to running, testing and developing within a project.

By using shell script, you can do more things the way you'd like.

Why a flow file?

Well, yaml is pretty easy to update and it's an interesting idea to create flow files for the projects you work on. In future iterations, we may add support to run flows from outside of vim.

vim-flow's People

Contributors

jonmorehouse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

vim-flow's Issues

Flow File

Ability to add in global flow-flags for directory

README

We need to update the readme:

  • features section
  • .flow.yml section
  • podcast?!
  • file locking
  • usage / installation

flow-binary idea

You know, using this more and more, I realized that there isn't anything particularly vim-specific about vim-flow in a lot of ways.

What if vim-flow became a small wrapper around a flow script, which was a standalone binary which could run commands.

Specifically, this would allow us to run commands from outside of vim and would make it much easier to bring vim-flow to new editors and things

better hierarchy

It almost seems like we need a "file" flow and a "project" flow concept.

For instance, I find myself working on a golang project with a yaml file or json file and would like to validate that file with my default work flow. It'd be great to call ProjectFlow and FileFlow.

Doesn't work with the default .flow.yml file

I am trying to use vim-flow with the default .flow.yml provided in the repo.
When I'm trying to :FlowRun any script, I get the following error:
'.flow.yml' file at $HOME/.flow.yml is not parseable yaml
Any idea how to fix it?

Shebang handlers

1.) Parse for a shebang

  • grab first line
  • check if two words, if one word then parse path, if two then take second
    2.) Check for programs that should be executed with this
    3.) Respect orders. Filename match should supercede everything else

regex parsing

So I'm currently working on gatekeeper which is a deeply structured go app. It seems to me like it'd be really nice to be able to run a flow for *_test.go files.

How would we support this? Well, one approach would be to try and see if the the .flow.yaml keep is a regex, and if it is, then we could use that to check the current buffer.

^.*_test.go$:
   cmd: go test -v .

Seems like this could be problematic WRT to escaping / handling special characters.

better approach to running commands

So right now we build commands and execute them directly... it seems to me like a better way to do this would be to treat each command as a unique script.

For instance... given the following command:

---
cmd: |
    clear && \
    if [[ ! -d /tmp/venv ]]; then echo "hi"; fi

We are going to try and wrap this into a single line command to send to tmux, and will have to deal with all sorts of issues around escaping and later unescaping characters.

What if we take a different approach:

  • check the command to see if it has a hashbang syntax, defaulting to whatever the current shell is in its place
  • write the command to a temporary file which is executable
  • send a command to tmux / vim to execute this file directly
  • remove the created file.

This also has the nice side effect of allowing us to do some more fun things in our flow files; for instance the above example now turns into:

---
cmd: | #!/usr/bin/zsh 
if [[ ! -d /tmp/venv ]];
     then echo "hi";
fi 

support filename specific commands

Thinking through some of the previous workflows that I had, I think it's sometimes helpful to specify a command for a specific filename.

For instance, let's say you are working on a Vagrantfile and want to run a vagrant command as part of your dev/test flow, we could support something like:

---
Vagrantfile:
     cmd: cd ~/vagrant && vagrant up

script deletion timing

I had to remove the bit of code that removes the temp script after we run it. Let's clean that up

less greedy service_defs loading

vim-flow greedily picks the first .flow.yml file it can find.

This is a problem in the case where I've declared a local .flow.yml file and only want to override a certain type of file (ie: I haven't declared an all block).

It seems to me like we ought to update flow.get_defs to accept an extension. We should continually walk the path upwards until we find a .flow.yml file which has either a corresponding extension block or an all block.

ability to specify whether or not we should create tmux pane?

Heh - I had this feature before, where vim-flow would try to make a best effort at creating the tmux pane/session.

A few thoughts ...

1.) we probably would want this to be optional
2.) to be fair, this is currently accomplishable by creating a standard cmd that controls tmux for you ...
3.) this would increase the surface area of each individual runner

Multiple commands per definition

So just thinking through a work flow I'm working on now ...

I've got a small server running in another window, and I'd love to 1.) build the server, 2.) start the server and 3.) curl the server fetching the response.

It'd be pretty awesome if I could set up several commands to do this for me. This is technically possible now, but it would be pretty elegant to be able to specify multiple commands for a single "flow" def.

Reload configuration

Flowconfig should reread the configuration each time, or just simply read from the variables.

refactoring / rebuild: simplify!!!

It seems to me like we can simplify this module drastically. Specifically, let's create the concept of a .flow.yml which declares all of the logic to handle a specific file runner.

A sample file looks like:

all: 
   tmux_pane: 1
   tmux_session: 0
   cmd: |
       echo {{filename}}

py: 
  cmd: |
       echo {{filename}}

It seems to me like we can make this stupid simple. VimFlow does the following:

  • identifies the current file's extension
  • walks up the directory path and fines the closest ".flow.yml"
  • fetches the extension command or the "all" command and executes it

We can remove all of the builtin flows, in favor of having users specify a .flow.yml. This should automagically re-load each file each time (there is no caching, anywhere) and runs the command in either the current window or a background tmux window.

We'll support the following variable templates:

templates = {
    "{{filename}}": os.path.abspath(filepath),
    "{{directory}}": os.path.dirname(filepath),
}

FWIW - we should still "lock" files, but it seems like almost everything else can go in favor of this simpler work flow.

handle multiline commands for vim runner

It looks like the following .flow.yml file breaks things:

---
py:
    cmd: | 
           cd ~ && \
           echo "test" && \
           echo "here"

Let's update the runner.vim_runner method to support this use case

neovim runner

Let's add a neovim runner which allows us to send output to a neovim buffer.

This will involve finding or creating the neovim term buffer and then calling a shell command that points to the flow script from within it.

handle missing tmux pane correctly

It looks like the tmux runner doesn't output too nicely for vim-flow. Specifically, we'll want to capture the stdout / stderr within vim and "print" it so that the dialog window disappears correctly and doesn't leave artifacts.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.