Viml projects: Difference between revisions

From wikinotes
 
(6 intermediate revisions by the same user not shown)
Line 15: Line 15:
# Project Hierarchy
# Project Hierarchy
vim-myproject/
vim-myproject/
  bin/
    testrun
   doc/
   doc/
     vim-myproject.txt
     vim-myproject.txt
Line 26: Line 28:
     test_foo.vader
     test_foo.vader
     test_bar.vader
     test_bar.vader
  Makefile
  .envrc
  .gitignore
</syntaxhighlight>
</syntaxhighlight>
{{ expand
| <code>bin/testrun</code>
|
A vader.vim test-runner script
<syntaxhighlight lang="bash">
#!/usr/bin/env bash
EXECUTABLE="$(basename "${BASH_SOURCE[0]}")"
setup_colours() {
    fg_comment=$(tput setaf 8)
    fg_preview=$(tput setaf 3)
    fg_normal=$(tput sgr0)
    fg_header=$(tput setaf 4)
}
show_help() {
    setup_colours
    echo "${fg_preview}${EXECUTABLE} [-i] [TESTFILE [TESTFILE...]]${fg_normal}"
    echo
    echo "${fg_header}DESCRIPTION:${fg_normal}"
    echo "    runs unittests (all by default)"
    echo
    echo "${fg_header}ARGUMENTS:${fg_normal}"
    echo "    -i --interactive"
    echo "        runs vader interactively (defaults to non-interactive)"
    echo
    echo "${fg_header}EXAMPLES:${fg_normal}"
    echo "    ${fg_comment}# run all tests, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE}"
    echo
    echo "    ${fg_comment}# run all tests, interactively${fg_normal}"
    echo "    ./${EXECUTABLE} -i"
    echo
    echo "    ${fg_comment}# run single testfile, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE} tests/viml/test_error.vader"
    echo
    echo "    ${fg_comment}# run multiple testfiles, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE} \\"
    echo "        tests/viml/test_error.vader \\"
    echo "        tests/viml/test_graphql.vader"
    echo
}
vimrc() {
cat <<-END
filetype off
set rtp+=.test_deps/vader.vim
set rtp+=.test_deps/jellybeans.vim
set rtp+=.
filetype plugin indent on
syntax enable
colorscheme jellybeans
map <leader>q :q<CR>
END
}
install_deps() {
    test -d .test_deps || mkdir -p .test_deps
    test -e .test_deps/vader.vim/.git || git clone https://github.com/junegunn/vader.vim .test_deps/vader.vim
    test -e .test_deps/jellybeans.vim/.git || git clone https://github.com/nanotech/jellybeans.vim  .test_deps/jellybeans.vim
}
run_tests() {
    args=$@
    if test -z "${args}" ; then
        default_tests='tests/*.vader'
    else
        default_tests=""
    fi
    if [[ "$interactive" == "1" ]] ; then
        vadercmd='+Vader '
        vadercmd+=" $default_tests"
        vim -Nu <(echo "$(vimrc)") "$vadercmd ${args[@]}"
    else
        vadercmd='Vader! '
        vadercmd+=" $default_tests"
        vim -Nu <(echo "$(vimrc)") -c "$vadercmd ${args[@]}" > /dev/null
    fi
}
main() {
    interactive=0
    args=$@
    while [ $# -gt 0 ] ; do
        case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -i|--interactive)
            interactive=1
            args=( "${args[@]/$1}" )
            shift
            ;;
        *)
            shift
            ;;
        esac
    done
    install_deps
    run_tests "${args[@]}"
}
main "$@"
</syntaxhighlight>
}}


{{ expand
{{ expand
Line 76: Line 201:


<syntaxhighlight lang="vim">
<syntaxhighlight lang="vim">
" don't reload if already loaded
if exists('myproject_plugin_loaded') || &cp
    finish
endif
let myproject_plugin_loaded=1
command Foo :call myproject#foo#do_foo()
command Foo :call myproject#foo#do_foo()
command Bar :call myproject#bar#do_bar()
command Bar :call myproject#bar#do_bar()
Line 112: Line 244:
Your [[VimPlugin: vader]] unit tests.
Your [[VimPlugin: vader]] unit tests.


<syntaxhighlight lang="vader">
<syntaxhighlight lang="bash">
Execute (test foo returns foo):
Execute (test foo returns foo):
   AssertEqual my_function("foo"), "foo"
   AssertEqual my_function("foo"), "foo"
Line 118: Line 250:
Execute (test bar returns bar):
Execute (test bar returns bar):
   AssertEqual my_function("bar"), "bar"
   AssertEqual my_function("bar"), "bar"
</syntaxhighlight>
}}
{{ expand
| <code>Makefile</code>
|
Simple instructions for common project tasks.
<syntaxhighlight lang="Makefile">
build:
    vim -Nu NONE -c 'helptags doc/' -c 'qa!'
test:
    bin/testrun
</syntaxhighlight>
}}
{{ expand
| <code>.envrc</code>
|
Adds <code>bin/</code> to $PATH when cd into directory if [[direnv]] is installed.
<syntaxhighlight lang="bash">
export PATH=$(pwd)/bin:$PATH
</syntaxhighlight>
}}
{{ expand
| <code>.gitignore</code>
|
Our test-runner installs local dependencies you won't want to commit with your plugin.
<syntaxhighlight lang="bash">
.test_deps/*
</syntaxhighlight>
</syntaxhighlight>


Line 124: Line 296:
</blockquote><!-- Example -->
</blockquote><!-- Example -->


= Basics =
= Directories =
<blockquote>
== Basics ==
<blockquote>
<blockquote>
viml does not have the concept of packages (like java, python, ...) but instead has plugins.
viml does not have the concept of packages (like java, python, ...) but instead has plugins.
Line 146: Line 320:
</blockquote><!-- basics -->
</blockquote><!-- basics -->


= autoload (packages) =
== autoload/) ==
<blockquote>
<blockquote>
Autoload solves the same problem as packages/imports in java/python.
Autoload solves the same problem as packages/imports in java/python.
Line 168: Line 342:
</blockquote><!-- autoload -->
</blockquote><!-- autoload -->


= ftplugin =
== ftplugin/ ==
<blockquote>
<blockquote>
ftplugin files are sourced (locally to buffer) if
ftplugin files are sourced (locally to buffer) if
Line 177: Line 351:
</blockquote><!-- ftplugin -->
</blockquote><!-- ftplugin -->


= plugin =
== plugin/ ==
<blockquote>
<blockquote>
This directory is loaded during vim startup.
This directory is loaded during vim startup.
Line 191: Line 365:
</source>
</source>
</blockquote><!-- plugin -->
</blockquote><!-- plugin -->
</blockquote><!-- Directories -->

Latest revision as of 19:49, 7 January 2023

This article describes viml project(plugin) file hierarchy. You may also want to see viml plugins.

Tutorials

steve losh plugin tutorial https://learnvimscriptthehardway.stevelosh.com/chapters/41.html

Example

# Project Hierarchy
vim-myproject/
  bin/
    testrun
  doc/
    vim-myproject.txt
  plugin/
    vim-myproject.vim
  autoload/
    myproject/
      foo.vim
      bar.vim
  tests/
    test_foo.vader
    test_bar.vader
  Makefile
  .envrc
  .gitignore

bin/testrun


A vader.vim test-runner script

#!/usr/bin/env bash
EXECUTABLE="$(basename "${BASH_SOURCE[0]}")"


setup_colours() {
    fg_comment=$(tput setaf 8)
    fg_preview=$(tput setaf 3)
    fg_normal=$(tput sgr0)
    fg_header=$(tput setaf 4)
}


show_help() {
    setup_colours

    echo "${fg_preview}${EXECUTABLE} [-i] [TESTFILE [TESTFILE...]]${fg_normal}"
    echo
    echo "${fg_header}DESCRIPTION:${fg_normal}"
    echo "    runs unittests (all by default)"
    echo
    echo "${fg_header}ARGUMENTS:${fg_normal}"
    echo "    -i --interactive"
    echo "        runs vader interactively (defaults to non-interactive)"
    echo
    echo "${fg_header}EXAMPLES:${fg_normal}"
    echo "    ${fg_comment}# run all tests, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE}"
    echo
    echo "    ${fg_comment}# run all tests, interactively${fg_normal}"
    echo "    ./${EXECUTABLE} -i"
    echo
    echo "    ${fg_comment}# run single testfile, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE} tests/viml/test_error.vader"
    echo
    echo "    ${fg_comment}# run multiple testfiles, non-interactively${fg_normal}"
    echo "    ./${EXECUTABLE} \\"
    echo "        tests/viml/test_error.vader \\"
    echo "        tests/viml/test_graphql.vader"
    echo
}


vimrc() {
cat <<-END
filetype off
set rtp+=.test_deps/vader.vim
set rtp+=.test_deps/jellybeans.vim
set rtp+=.
filetype plugin indent on
syntax enable
colorscheme jellybeans
map <leader>q :q<CR>
END
}


install_deps() {
    test -d .test_deps || mkdir -p .test_deps
    test -e .test_deps/vader.vim/.git || git clone https://github.com/junegunn/vader.vim .test_deps/vader.vim
    test -e .test_deps/jellybeans.vim/.git || git clone https://github.com/nanotech/jellybeans.vim  .test_deps/jellybeans.vim
}


run_tests() {
    args=$@
    if test -z "${args}" ; then
        default_tests='tests/*.vader'
    else
        default_tests=""
    fi

    if [[ "$interactive" == "1" ]] ; then
        vadercmd='+Vader '
        vadercmd+=" $default_tests"
        vim -Nu <(echo "$(vimrc)") "$vadercmd ${args[@]}"
    else
        vadercmd='Vader! '
        vadercmd+=" $default_tests"
        vim -Nu <(echo "$(vimrc)") -c "$vadercmd ${args[@]}" > /dev/null
    fi
}


main() {
    interactive=0
    args=$@
    while [ $# -gt 0 ] ; do
        case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -i|--interactive)
            interactive=1
            args=( "${args[@]/$1}" )
            shift
            ;;
        *)
            shift
            ;;
        esac
    done

    install_deps
    run_tests "${args[@]}"
}


main "$@"


doc/vim-myproject.txt


The helpfile. You'll need to build the search index with :helptags doc/.
For more details, see vim helpfile syntax.

*vim-myproject.txt*                                  A Sample skeleton project.

Author   Mara Jade
License  MIT

================================================================================
CONTENTS                                                      *myproject-contents*
================================================================================

    1.Introduction.....................myproject-intro
        1.1.History
    2.Usage............................myproject-usage
        2.1.Default Key Bindings
    3.Commands.........................myproject-commands


1. INTRODUCTION                                                  *myproject-intro*
================================================================================

    A sample skeleton project, to use as a base for your own plugins.


2. KEY-BINDINGS                                            *myproject-keybindings*
================================================================================
>
    <leader>foo   " runs Foo
    <leader>bar   " runs Bar
<
================================================================================
vim:tw=78:et:ft=help:norl

plugin/vim-myproject.vim


Read on vim startup, this is generally the entrypoint for your plugin (unless it's syntax, indent, etc).

" don't reload if already loaded
if exists('myproject_plugin_loaded') || &cp
    finish
endif
let myproject_plugin_loaded=1


command Foo :call myproject#foo#do_foo()
command Bar :call myproject#bar#do_bar()

nnoremap <leader>foo :Foo<CR>
nnoremap <leader>bar :Bar<CR>


autoload/myproject/*.vim


These files are only read when referenced.
The functions are namespaced, and must match the directory hierarchy.

function! myproject#foo#do_foo()
    return 'foo'
endfunc
function! myproject#bar#do_bar()
    return 'bar'
endfunc


tests/test_*.vader


Your VimPlugin: vader unit tests.

Execute (test foo returns foo):
  AssertEqual my_function("foo"), "foo"

Execute (test bar returns bar):
  AssertEqual my_function("bar"), "bar"


Makefile


Simple instructions for common project tasks.

build:
    vim -Nu NONE -c 'helptags doc/' -c 'qa!'

test:
    bin/testrun


.envrc


Adds bin/ to $PATH when cd into directory if direnv is installed.

export PATH=$(pwd)/bin:$PATH


.gitignore


Our test-runner installs local dependencies you won't want to commit with your plugin.

.test_deps/*


Directories

Basics

viml does not have the concept of packages (like java, python, ...) but instead has plugins.

Plugin shares the same directory structure as your ~/.vim directory, are added to the vim runtime path, and loaded with vim. See /usr/share/vim/vim81 for an example.

example:

~/.vim/bundles/yourplugin/
    autoload/   # source called
    colors/     # colorschemes
    doc/        # vim help files
    ftplugin/   # sourced (into buffer) if filetype matches filename
    plugin/     # sourced on vim-startup
    syntax/     # syntax files
    tools/      # standalone cli tools (like bin/)

    after/{syntax,colors,autoload,...}   # load after vim

autoload/)

Autoload solves the same problem as packages/imports in java/python. These source files are not read until one of their commands is invoked. No sourcing required.

" ~/.vim/bundles/yourplugin/autoload/filesystem/unix.vim
"                                   {filesystem}#{unix}   <-- see

function! filesystem#unix#normalize_path(filepath)
    let normalized_filepath = substitute(a:filepath, '\\', '/', 'g')
    return normalized_filepath
endfunc


calling autoload functions simply refers to the file on the path.

call filesystem#unix#normalize_path('\\a\\b\\c')

ftplugin/

ftplugin files are sourced (locally to buffer) if

  • their filename matches current buffer's filetype (ex: 'python.vim' is read when reading a '.py' file)
  • they are in a directory whose name matches current buffer's filetype (ex: 'python/pymode.vim' is read when reading a '.py' file)

plugin/

This directory is loaded during vim startup.

You should skip reloading these files if they have already been loaded
otherwise some plugin managers may trip over them.

if exists('XXXXX_plugin_loaded') || &cp
    finish
endif
let XXXXX_plugin_loaded=1