Viml projects

From wikinotes
Revision as of 19:49, 7 January 2023 by Will (talk | contribs) (→‎Example)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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