summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--README.md3
-rw-r--r--autoload/zig/config.vim43
-rw-r--r--autoload/zig/fmt.vim170
-rw-r--r--autoload/zig/list.vim162
-rw-r--r--autoload/zig/util.vim394
-rwxr-xr-xbuild1
-rw-r--r--ftdetect/polyglot.vim7
-rw-r--r--ftplugin/zig.vim18
-rw-r--r--syntax/zig.vim106
9 files changed, 903 insertions, 1 deletions
diff --git a/README.md b/README.md
index 978491e7..79e75008 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ A collection of language packs for Vim.
> One to rule them all, one to find them, one to bring them all and in the darkness bind them.
- It **won't affect your startup time**, as scripts are loaded only on demand\*.
-- It **installs and updates 120+ times faster** than the <!--Package Count-->140<!--/Package Count--> packages it consists of.
+- It **installs and updates 120+ times faster** than the <!--Package Count-->141<!--/Package Count--> packages it consists of.
- Solid syntax and indentation support (other features skipped). Only the best language packs.
- All unnecessary files are ignored (like enormous documentation from php support).
- No support for esoteric languages, only most popular ones (modern too, like `slim`).
@@ -185,6 +185,7 @@ If you need full functionality of any plugin, please use it directly with your p
- [xml](https://github.com/amadeus/vim-xml) (syntax)
- [yaml](https://github.com/stephpy/vim-yaml) (syntax, ftplugin)
- [yard](https://github.com/sheerun/vim-yardoc) (syntax)
+- [zig](https://github.com/ziglang/zig.vim) (syntax, autoload, ftplugin)
<!--/Language Packs-->
## Updating
diff --git a/autoload/zig/config.vim b/autoload/zig/config.vim
new file mode 100644
index 00000000..9a87fa1c
--- /dev/null
+++ b/autoload/zig/config.vim
@@ -0,0 +1,43 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+function! zig#config#ListTypeCommands() abort
+ return get(g:, 'zig_list_type_commands', {})
+endfunction
+
+function! zig#config#ListType() abort
+ return get(g:, 'zig_list_type', '')
+endfunction
+
+function! zig#config#ListAutoclose() abort
+ return get(g:, 'zig_list_autoclose', 1)
+endfunction
+
+function! zig#config#ListHeight() abort
+ return get(g:, "zig_list_height", 0)
+endfunction
+
+function! zig#config#FmtAutosave() abort
+ return get(g:, "zig_fmt_autosave", 0)
+endfunction
+
+function! zig#config#SetFmtAutosave(value) abort
+ let g:zig_fmt_autosave = a:value
+endfunction
+
+function! zig#config#FmtCommand() abort
+ return get(g:, "zig_fmt_command", ['zig', 'fmt', '--color', 'off'])
+endfunction
+
+function! zig#config#FmtFailSilently() abort
+ return get(g:, "zig_fmt_fail_silently", 0)
+endfunction
+
+function! zig#config#FmtExperimental() abort
+ return get(g:, "zig_fmt_experimental", 0)
+endfunction
+
+function! zig#config#Debug() abort
+ return get(g:, 'zig_debug', [])
+endfunction
diff --git a/autoload/zig/fmt.vim b/autoload/zig/fmt.vim
new file mode 100644
index 00000000..cc7862c7
--- /dev/null
+++ b/autoload/zig/fmt.vim
@@ -0,0 +1,170 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+" Adapted from fatih/vim-go: autoload/go/fmt.vim
+"
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+function! zig#fmt#Format() abort
+ if zig#config#FmtExperimental()
+ " Using winsaveview to save/restore cursor state has the problem of
+ " closing folds on save:
+ " https://github.com/fatih/vim-go/issues/502
+ " One fix is to use mkview instead. Unfortunately, this sometimes causes
+ " other bad side effects:
+ " https://github.com/fatih/vim-go/issues/728
+ " and still closes all folds if foldlevel>0:
+ " https://github.com/fatih/vim-go/issues/732
+ let l:curw = {}
+ try
+ mkview!
+ catch
+ let l:curw = winsaveview()
+ endtry
+
+ " save our undo file to be restored after we are done. This is needed to
+ " prevent an additional undo jump due to BufWritePre auto command and also
+ " restore 'redo' history because it's getting being destroyed every
+ " BufWritePre
+ let tmpundofile = tempname()
+ exe 'wundo! ' . tmpundofile
+ else
+ " Save cursor position and many other things.
+ let l:curw = winsaveview()
+ endif
+
+ " Save cursor position and many other things.
+ let l:curw = winsaveview()
+
+ let bin_name = zig#config#FmtCommand()
+
+ " Get current position in file
+ let current_col = col('.')
+ let orig_line_count = line('$')
+
+ " Save current buffer first, else fmt will run on the original file and we
+ " will lose our changes.
+ silent! execute 'write' expand('%')
+
+ let [l:out, l:err] = zig#fmt#run(bin_name, expand('%'))
+
+ if l:err == 0
+ call zig#fmt#update_file(expand('%'))
+ elseif !zig#config#FmtFailSilently()
+ let errors = s:parse_errors(expand('%'), out)
+ call s:show_errors(errors)
+ endif
+
+ let diff_offset = line('$') - orig_line_count
+
+ if zig#config#FmtExperimental()
+ " restore our undo history
+ silent! exe 'rundo ' . tmpundofile
+ call delete(tmpundofile)
+
+ " Restore our cursor/windows positions, folds, etc.
+ if empty(l:curw)
+ silent! loadview
+ else
+ call winrestview(l:curw)
+ endif
+ else
+ " Restore our cursor/windows positions.
+ call winrestview(l:curw)
+ endif
+
+ " be smart and jump to the line the new statement was added/removed
+ call cursor(line('.') + diff_offset, current_col)
+
+ " Syntax highlighting breaks less often.
+ syntax sync fromstart
+endfunction
+
+" update_file updates the target file with the given formatted source
+function! zig#fmt#update_file(target)
+ " remove undo point caused via BufWritePre
+ try | silent undojoin | catch | endtry
+
+ " reload buffer to reflect latest changes
+ silent edit!
+
+ let l:listtype = zig#list#Type("ZigFmt")
+
+ " the title information was introduced with 7.4-2200
+ " https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
+ if has('patch-7.4.2200')
+ " clean up previous list
+ if l:listtype == "quickfix"
+ let l:list_title = getqflist({'title': 1})
+ else
+ let l:list_title = getloclist(0, {'title': 1})
+ endif
+ else
+ " can't check the title, so assume that the list was for go fmt.
+ let l:list_title = {'title': 'Format'}
+ endif
+
+ if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
+ call zig#list#Clean(l:listtype)
+ endif
+endfunction
+
+" run runs the gofmt/goimport command for the given source file and returns
+" the output of the executed command. Target is the real file to be formatted.
+function! zig#fmt#run(bin_name, target)
+ let l:cmd = []
+ call extend(cmd, a:bin_name)
+ call extend(cmd, [a:target])
+ return zig#util#Exec(l:cmd)
+endfunction
+
+" parse_errors parses the given errors and returns a list of parsed errors
+function! s:parse_errors(filename, content) abort
+ let splitted = split(a:content, '\n')
+
+ " list of errors to be put into location list
+ let errors = []
+ for line in splitted
+ let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
+ if !empty(tokens)
+ call add(errors,{
+ \"filename": a:filename,
+ \"lnum": tokens[2],
+ \"col": tokens[3],
+ \"text": tokens[4],
+ \ })
+ endif
+ endfor
+
+ return errors
+endfunction
+
+" show_errors opens a location list and shows the given errors. If the given
+" errors is empty, it closes the the location list
+function! s:show_errors(errors) abort
+ let l:listtype = zig#list#Type("ZigFmt")
+ if !empty(a:errors)
+ call zig#list#Populate(l:listtype, a:errors, 'Format')
+ echohl Error | echomsg "zig fmt returned error" | echohl None
+ endif
+
+ " this closes the window if there are no errors or it opens
+ " it if there is any
+ call zig#list#Window(l:listtype, len(a:errors))
+endfunction
+
+function! zig#fmt#ToggleFmtAutoSave() abort
+ if zig#config#FmtAutosave()
+ call zig#config#SetFmtAutosave(0)
+ call zig#util#EchoProgress("auto fmt disabled")
+ return
+ end
+
+ call zig#config#SetFmtAutosave(1)
+ call zig#util#EchoProgress("auto fmt enabled")
+endfunction
+
+" vim: sw=2 ts=2 et
diff --git a/autoload/zig/list.vim b/autoload/zig/list.vim
new file mode 100644
index 00000000..97ebf47f
--- /dev/null
+++ b/autoload/zig/list.vim
@@ -0,0 +1,162 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+" Adapted from fatih/vim-go: autoload/go/list.vim
+"
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+
+" Window opens the list with the given height up to 10 lines maximum.
+" Otherwise g:zig_loclist_height is used.
+"
+" If no or zero height is given it closes the window by default.
+" To prevent this, set g:zig_list_autoclose = 0
+function! zig#list#Window(listtype, ...) abort
+ " we don't use lwindow to close the location list as we need also the
+ " ability to resize the window. So, we are going to use lopen and lclose
+ " for a better user experience. If the number of errors in a current
+ " location list increases/decreases, cwindow will not resize when a new
+ " updated height is passed. lopen in the other hand resizes the screen.
+ if !a:0 || a:1 == 0
+ call zig#list#Close(a:listtype)
+ return
+ endif
+
+ let height = zig#config#ListHeight()
+ if height == 0
+ " prevent creating a large location height for a large set of numbers
+ if a:1 > 10
+ let height = 10
+ else
+ let height = a:1
+ endif
+ endif
+
+ if a:listtype == "locationlist"
+ exe 'lopen ' . height
+ else
+ exe 'copen ' . height
+ endif
+endfunction
+
+
+" Get returns the current items from the list
+function! zig#list#Get(listtype) abort
+ if a:listtype == "locationlist"
+ return getloclist(0)
+ else
+ return getqflist()
+ endif
+endfunction
+
+" Populate populate the list with the given items
+function! zig#list#Populate(listtype, items, title) abort
+ if a:listtype == "locationlist"
+ call setloclist(0, a:items, 'r')
+
+ " The last argument ({what}) is introduced with 7.4.2200:
+ " https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
+ if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
+ else
+ call setqflist(a:items, 'r')
+ if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
+ endif
+endfunction
+
+" Parse parses the given items based on the specified errorformat and
+" populates the list.
+function! zig#list#ParseFormat(listtype, errformat, items, title) abort
+ " backup users errorformat, will be restored once we are finished
+ let old_errorformat = &errorformat
+
+ " parse and populate the location list
+ let &errorformat = a:errformat
+ try
+ call zig#list#Parse(a:listtype, a:items, a:title)
+ finally
+ "restore back
+ let &errorformat = old_errorformat
+ endtry
+endfunction
+
+" Parse parses the given items based on the global errorformat and
+" populates the list.
+function! zig#list#Parse(listtype, items, title) abort
+ if a:listtype == "locationlist"
+ lgetexpr a:items
+ if has("patch-7.4.2200") | call setloclist(0, [], 'a', {'title': a:title}) | endif
+ else
+ cgetexpr a:items
+ if has("patch-7.4.2200") | call setqflist([], 'a', {'title': a:title}) | endif
+ endif
+endfunction
+
+" JumpToFirst jumps to the first item in the location list
+function! zig#list#JumpToFirst(listtype) abort
+ if a:listtype == "locationlist"
+ ll 1
+ else
+ cc 1
+ endif
+endfunction
+
+" Clean cleans and closes the location list
+function! zig#list#Clean(listtype) abort
+ if a:listtype == "locationlist"
+ lex []
+ else
+ cex []
+ endif
+
+ call zig#list#Close(a:listtype)
+endfunction
+
+" Close closes the location list
+function! zig#list#Close(listtype) abort
+ let autoclose_window = zig#config#ListAutoclose()
+ if !autoclose_window
+ return
+ endif
+
+ if a:listtype == "locationlist"
+ lclose
+ else
+ cclose
+ endif
+endfunction
+
+function! s:listtype(listtype) abort
+ let listtype = zig#config#ListType()
+ if empty(listtype)
+ return a:listtype
+ endif
+
+ return listtype
+endfunction
+
+" s:default_list_type_commands is the defaults that will be used for each of
+" the supported commands (see documentation for g:zig_list_type_commands). When
+" defining a default, quickfix should be used if the command operates on
+" multiple files, while locationlist should be used if the command operates on a
+" single file or buffer. Keys that begin with an underscore are not supported
+" in g:zig_list_type_commands.
+let s:default_list_type_commands = {
+ \ "ZigFmt": "locationlist",
+ \ }
+
+function! zig#list#Type(for) abort
+ let l:listtype = s:listtype(get(s:default_list_type_commands, a:for))
+ if l:listtype == "0"
+ call zig#util#EchoError(printf(
+ \ "unknown list type command value found ('%s'). Please open a bug report in the zig.vim repo.",
+ \ a:for))
+ let l:listtype = "quickfix"
+ endif
+
+ return get(zig#config#ListTypeCommands(), a:for, l:listtype)
+endfunction
+
+" vim: sw=2 ts=2 et
diff --git a/autoload/zig/util.vim b/autoload/zig/util.vim
new file mode 100644
index 00000000..bb2df40c
--- /dev/null
+++ b/autoload/zig/util.vim
@@ -0,0 +1,394 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+" Adapted from vim-go: autoload/go/util.vim
+"
+" Copyright 2011 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
+"
+
+" PathSep returns the appropriate OS specific path separator.
+function! zig#util#PathSep() abort
+ if zig#util#IsWin()
+ return '\'
+ endif
+ return '/'
+endfunction
+
+" PathListSep returns the appropriate OS specific path list separator.
+function! zig#util#PathListSep() abort
+ if zig#util#IsWin()
+ return ";"
+ endif
+ return ":"
+endfunction
+
+" LineEnding returns the correct line ending, based on the current fileformat
+function! zig#util#LineEnding() abort
+ if &fileformat == 'dos'
+ return "\r\n"
+ elseif &fileformat == 'mac'
+ return "\r"
+ endif
+
+ return "\n"
+endfunction
+
+" Join joins any number of path elements into a single path, adding a
+" Separator if necessary and returns the result
+function! zig#util#Join(...) abort
+ return join(a:000, zig#util#PathSep())
+endfunction
+
+" IsWin returns 1 if current OS is Windows or 0 otherwise
+function! zig#util#IsWin() abort
+ let win = ['win16', 'win32', 'win64', 'win95']
+ for w in win
+ if (has(w))
+ return 1
+ endif
+ endfor
+
+ return 0
+endfunction
+
+" IsMac returns 1 if current OS is macOS or 0 otherwise.
+function! zig#util#IsMac() abort
+ return has('mac') ||
+ \ has('macunix') ||
+ \ has('gui_macvim') ||
+ \ zig#util#Exec(['uname'])[0] =~? '^darwin'
+endfunction
+
+ " Checks if using:
+ " 1) Windows system,
+ " 2) And has cygpath executable,
+ " 3) And uses *sh* as 'shell'
+function! zig#util#IsUsingCygwinShell()
+ return zig#util#IsWin() && executable('cygpath') && &shell =~ '.*sh.*'
+endfunction
+
+" Check if Vim jobs API is supported.
+"
+" The (optional) first paramter can be added to indicate the 'cwd' or 'env'
+" parameters will be used, which wasn't added until a later version.
+function! zig#util#has_job(...) abort
+ " cwd and env parameters to job_start was added in this version.
+ if a:0 > 0 && a:1 is 1
+ return has('job') && has("patch-8.0.0902")
+ endif
+
+ " job was introduced in 7.4.xxx however there are multiple bug fixes and one
+ " of the latest is 8.0.0087 which is required for a stable async API.
+ return has('job') && has("patch-8.0.0087")
+endfunction
+
+let s:env_cache = {}
+
+" env returns the go environment variable for the given key. Where key can be
+" GOARCH, GOOS, GOROOT, etc... It caches the result and returns the cached
+" version.
+function! zig#util#env(key) abort
+ let l:key = tolower(a:key)
+ if has_key(s:env_cache, l:key)
+ return s:env_cache[l:key]
+ endif
+
+ if executable('go')
+ let l:var = call('zig#util#'.l:key, [])
+ if zig#util#ShellError() != 0
+ call zig#util#EchoError(printf("'go env %s' failed", toupper(l:key)))
+ return ''
+ endif
+ else
+ let l:var = eval("$".toupper(a:key))
+ endif
+
+ let s:env_cache[l:key] = l:var
+ return l:var
+endfunction
+
+" Run a shell command.
+"
+" It will temporary set the shell to /bin/sh for Unix-like systems if possible,
+" so that we always use a standard POSIX-compatible Bourne shell (and not e.g.
+" csh, fish, etc.) See #988 and #1276.
+function! s:system(cmd, ...) abort
+ " Preserve original shell and shellredir values
+ let l:shell = &shell
+ let l:shellredir = &shellredir
+
+ if !zig#util#IsWin() && executable('/bin/sh')
+ set shell=/bin/sh shellredir=>%s\ 2>&1
+ endif
+
+ try
+ return call('system', [a:cmd] + a:000)
+ finally
+ " Restore original values
+ let &shell = l:shell
+ let &shellredir = l:shellredir
+ endtry
+endfunction
+
+" System runs a shell command "str". Every arguments after "str" is passed to
+" stdin.
+function! zig#util#System(str, ...) abort
+ return call('s:system', [a:str] + a:000)
+endfunction
+
+" Exec runs a shell command "cmd", which must be a list, one argument per item.
+" Every list entry will be automatically shell-escaped
+" Every other argument is passed to stdin.
+function! zig#util#Exec(cmd, ...) abort
+ if len(a:cmd) == 0
+ call zig#util#EchoError("zig#util#Exec() called with empty a:cmd")
+ return ['', 1]
+ endif
+
+ let l:bin = a:cmd[0]
+
+ if !executable(l:bin)
+ call zig#util#EchoError(printf("could not find binary '%s'", a:cmd[0]))
+ return ['', 1]
+ endif
+
+ return call('s:exec', [a:cmd] + a:000)
+endfunction
+
+function! s:exec(cmd, ...) abort
+ let l:bin = a:cmd[0]
+ let l:cmd = zig#util#Shelljoin([l:bin] + a:cmd[1:])
+ if zig#util#HasDebug('shell-commands')
+ call zig#util#EchoInfo('shell command: ' . l:cmd)
+ endif
+
+ let l:out = call('s:system', [l:cmd] + a:000)
+ return [l:out, zig#util#ShellError()]
+endfunction
+
+function! zig#util#ShellError() abort
+ return v:shell_error
+endfunction
+
+" StripPath strips the path's last character if it's a path separator.
+" example: '/foo/bar/' -> '/foo/bar'
+function! zig#util#StripPathSep(path) abort
+ let last_char = strlen(a:path) - 1
+ if a:path[last_char] == zig#util#PathSep()
+ return strpart(a:path, 0, last_char)
+ endif
+
+ return a:path
+endfunction
+
+" StripTrailingSlash strips the trailing slash from the given path list.
+" example: ['/foo/bar/'] -> ['/foo/bar']
+function! zig#util#StripTrailingSlash(paths) abort
+ return map(copy(a:paths), 'zig#util#StripPathSep(v:val)')
+endfunction
+
+" Shelljoin returns a shell-safe string representation of arglist. The
+" {special} argument of shellescape() may optionally be passed.
+function! zig#util#Shelljoin(arglist, ...) abort
+ try
+ let ssl_save = &shellslash
+ set noshellslash
+ if a:0
+ return join(map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')'), ' ')
+ endif
+
+ return join(map(copy(a:arglist), 'shellescape(v:val)'), ' ')
+ finally
+ let &shellslash = ssl_save
+ endtry
+endfunction
+
+fu! zig#util#Shellescape(arg)
+ try
+ let ssl_save = &shellslash
+ set noshellslash
+ return shellescape(a:arg)
+ finally
+ let &shellslash = ssl_save
+ endtry
+endf
+
+" Shelllist returns a shell-safe representation of the items in the given
+" arglist. The {special} argument of shellescape() may optionally be passed.
+function! zig#util#Shelllist(arglist, ...) abort
+ try
+ let ssl_save = &shellslash
+ set noshellslash
+ if a:0
+ return map(copy(a:arglist), 'shellescape(v:val, ' . a:1 . ')')
+ endif
+ return map(copy(a:arglist), 'shellescape(v:val)')
+ finally
+ let &shellslash = ssl_save
+ endtry
+endfunction
+
+" Returns the byte offset for line and column
+function! zig#util#Offset(line, col) abort
+ if &encoding != 'utf-8'
+ let sep = zig#util#LineEnding()
+ let buf = a:line == 1 ? '' : (join(getline(1, a:line-1), sep) . sep)
+ let buf .= a:col == 1 ? '' : getline('.')[:a:col-2]
+ return len(iconv(buf, &encoding, 'utf-8'))
+ endif
+ return line2byte(a:line) + (a:col-2)
+endfunction
+"
+" Returns the byte offset for the cursor
+function! zig#util#OffsetCursor() abort
+ return zig#util#Offset(line('.'), col('.'))
+endfunction
+
+" Windo is like the built-in :windo, only it returns to the window the command
+" was issued from
+function! zig#util#Windo(command) abort
+ let s:currentWindow = winnr()
+ try
+ execute "windo " . a:command
+ finally
+ execute s:currentWindow. "wincmd w"
+ unlet s:currentWindow
+ endtry
+endfunction
+
+" snippetcase converts the given word to given preferred snippet setting type
+" case.
+function! zig#util#snippetcase(word) abort
+ let l:snippet_case = zig#config#AddtagsTransform()
+ if l:snippet_case == "snakecase"
+ return zig#util#snakecase(a:word)
+ elseif l:snippet_case == "camelcase"
+ return zig#util#camelcase(a:word)
+ else
+ return a:word " do nothing
+ endif
+endfunction
+
+" snakecase converts a string to snake case. i.e: FooBar -> foo_bar
+" Copied from tpope/vim-abolish
+function! zig#util#snakecase(word) abort
+ let word = substitute(a:word, '::', '/', 'g')
+ let word = substitute(word, '\(\u\+\)\(\u\l\)', '\1_\2', 'g')
+ let word = substitute(word, '\(\l\|\d\)\(\u\)', '\1_\2', 'g')
+ let word = substitute(word, '[.-]', '_', 'g')
+ let word = tolower(word)
+ return word
+endfunction
+
+" camelcase converts a string to camel case. e.g. FooBar or foo_bar will become
+" fooBar.
+" Copied from tpope/vim-abolish.
+function! zig#util#camelcase(word) abort
+ let word = substitute(a:word, '-', '_', 'g')
+ if word !~# '_' && word =~# '\l'
+ return substitute(word, '^.', '\l&', '')
+ else
+ return substitute(word, '\C\(_\)\=\(.\)', '\=submatch(1)==""?tolower(submatch(2)) : toupper(submatch(2))','g')
+ endif
+endfunction
+
+" pascalcase converts a string to 'PascalCase'. e.g. fooBar or foo_bar will
+" become FooBar.
+function! zig#util#pascalcase(word) abort
+ let word = zig#util#camelcase(a:word)
+ return toupper(word[0]) . word[1:]
+endfunction
+
+" Echo a message to the screen and highlight it with the group in a:hi.
+"
+" The message can be a list or string; every line with be :echomsg'd separately.
+function! s:echo(msg, hi)
+ let l:msg = []
+ if type(a:msg) != type([])
+ let l:msg = split(a:msg, "\n")
+ else
+ let l:msg = a:msg
+ endif
+
+ " Tabs display as ^I or <09>, so manually expand them.
+ let l:msg = map(l:msg, 'substitute(v:val, "\t", " ", "")')
+
+ exe 'echohl ' . a:hi
+ for line in l:msg
+ echom "zig.vim: " . line
+ endfor
+ echohl None
+endfunction
+
+function! zig#util#EchoSuccess(msg)
+ call s:echo(a:msg, 'Function')
+endfunction
+function! zig#util#EchoError(msg)
+ call s:echo(a:msg, 'ErrorMsg')
+endfunction
+function! zig#util#EchoWarning(msg)
+ call s:echo(a:msg, 'WarningMsg')
+endfunction
+function! zig#util#EchoProgress(msg)
+ redraw
+ call s:echo(a:msg, 'Identifier')
+endfunction
+function! zig#util#EchoInfo(msg)
+ call s:echo(a:msg, 'Debug')
+endfunction
+
+" Get all lines in the buffer as a a list.
+function! zig#util#GetLines()
+ let buf = getline(1, '$')
+ if &encoding != 'utf-8'
+ let buf = map(buf, 'iconv(v:val, &encoding, "utf-8")')
+ endif
+ if &l:fileformat == 'dos'
+ " XXX: line2byte() depend on 'fileformat' option.
+ " so if fileformat is 'dos', 'buf' must include '\r'.
+ let buf = map(buf, 'v:val."\r"')
+ endif
+ return buf
+endfunction
+
+" Make a named temporary directory which starts with "prefix".
+"
+" Unfortunately Vim's tempname() is not portable enough across various systems;
+" see: https://github.com/mattn/vim-go/pull/3#discussion_r138084911
+function! zig#util#tempdir(prefix) abort
+ " See :help tempfile
+ if zig#util#IsWin()
+ let l:dirs = [$TMP, $TEMP, 'c:\tmp', 'c:\temp']
+ else
+ let l:dirs = [$TMPDIR, '/tmp', './', $HOME]
+ endif
+
+ let l:dir = ''
+ for l:d in dirs
+ if !empty(l:d) && filewritable(l:d) == 2
+ let l:dir = l:d
+ break
+ endif
+ endfor
+
+ if l:dir == ''
+ call zig#util#EchoError('Unable to find directory to store temporary directory in')
+ return
+ endif
+
+ " Not great randomness, but "good enough" for our purpose here.
+ let l:rnd = sha256(printf('%s%s', localtime(), fnamemodify(bufname(''), ":p")))
+ let l:tmp = printf("%s/%s%s", l:dir, a:prefix, l:rnd)
+ call mkdir(l:tmp, 'p', 0700)
+ return l:tmp
+endfunction
+
+" Report if the user enabled a debug flag in g:zig_debug.
+function! zig#util#HasDebug(flag)
+ return index(zig#config#Debug(), a:flag) >= 0
+endfunction
+
+" vim: sw=2 ts=2 et
diff --git a/build b/build
index 6b3dec30..e447e836 100755
--- a/build
+++ b/build
@@ -293,6 +293,7 @@ PACKS="
xls:vim-scripts/XSLT-syntax
yaml:stephpy/vim-yaml
yard:sheerun/vim-yardoc
+ zig:ziglang/zig.vim
"
rm -rf tmp
diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim
index 48c6e61e..f66f72c5 100644
--- a/ftdetect/polyglot.vim
+++ b/ftdetect/polyglot.vim
@@ -1449,3 +1449,10 @@ autocmd BufNewFile,BufRead *.xdc setfiletype xdc
augroup end
endif
+if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'zig') == -1
+ augroup filetypedetect
+ " zig, from zig.vim in ziglang/zig.vim
+au BufRead,BufNewFile *.zig set filetype=zig
+ augroup end
+endif
+
diff --git a/ftplugin/zig.vim b/ftplugin/zig.vim
new file mode 100644
index 00000000..38008957
--- /dev/null
+++ b/ftplugin/zig.vim
@@ -0,0 +1,18 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+" Only do this when not done yet for this buffer
+if (exists("b:did_ftplugin"))
+ finish
+endif
+
+let b:did_ftplugin = 1
+
+set expandtab
+set tabstop=4
+set shiftwidth=4
+
+setlocal suffixesadd=.zig
+setlocal commentstring=//\ %s
+setlocal makeprg=zig\ build
diff --git a/syntax/zig.vim b/syntax/zig.vim
new file mode 100644
index 00000000..05e29d5f
--- /dev/null
+++ b/syntax/zig.vim
@@ -0,0 +1,106 @@
+if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'zig') != -1
+ finish
+endif
+
+" Vim syntax file
+" Language: Zig
+" Maintainer: Andrew Kelley
+" Latest Revision: 03 August 2016
+
+if exists("b:current_syntax")
+ finish
+endif
+let b:current_syntax = "zig"
+
+syn keyword zigStorage const var extern packed export pub noalias inline comptime nakedcc stdcallcc volatile allowzero align linksection threadlocal
+syn keyword zigStructure struct enum union error
+syn keyword zigStatement break return continue asm defer errdefer unreachable try catch async await suspend resume cancel
+syn keyword zigConditional if else switch and or orelse
+syn keyword zigRepeat while for
+
+syn keyword zigConstant null undefined
+syn keyword zigKeyword fn usingnamespace test
+syn keyword zigType bool f16 f32 f64 f128 void noreturn type anyerror promise
+syn keyword zigType i0 u0 isize usize comptime_int comptime_float
+syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong c_longdouble c_void
+
+syn keyword zigBoolean true false
+
+syn match zigType "\v<[iu][1-9]\d*>"
+
+syn match zigOperator display "\%(+%\?\|-%\?\|/\|*%\?\|=\|\^\|&\|?\||\|!\|>\|<\|%\|<<%\?\|>>\)=\?"
+syn match zigArrowCharacter display "->"
+
+syn match zigBuiltinFn "\v\@(addWithOverflow|ArgType|atomicLoad|bitCast|breakpoint)>"
+syn match zigBuiltinFn "\v\@(alignCast|alignOf|cDefine|cImport|cInclude)>"
+syn match zigBuiltinFn "\v\@(cUndef|canImplicitCast|clz|cmpxchgWeak|cmpxchgStrong|compileError)>"
+syn match zigBuiltinFn "\v\@(compileLog|ctz|popCount|divExact|divFloor|divTrunc)>"
+syn match zigBuiltinFn "\v\@(embedFile|export|tagName|TagType|errorName)>"
+syn match zigBuiltinFn "\v\@(errorReturnTrace|fence|fieldParentPtr|field)>"
+syn match zigBuiltinFn "\v\@(frameAddress|import|inlineCall|newStackCall|intToPtr|IntType)>"
+syn match zigBuiltinFn "\v\@(maxValue|memberCount|memberName|memberType)>"
+syn match zigBuiltinFn "\v\@(memcpy|memset|minValue|mod|mulWithOverflow)>"
+syn match zigBuiltinFn "\v\@(noInlineCall|bitOffsetOf|byteOffsetOf|OpaqueType|panic|ptrCast)>"
+syn match zigBuiltinFn "\v\@(ptrToInt|rem|returnAddress|setCold)>"
+syn match zigBuiltinFn "\v\@(setRuntimeSafety|setEvalBranchQuota|setFloatMode)>"
+syn match zigBuiltinFn "\v\@(setGlobalLinkage|setGlobalSection|shlExact|This|hasDecl)>"
+syn match zigBuiltinFn "\v\@(shlWithOverflow|shrExact|sizeOf|sqrt|bswap|subWithOverflow|intCast|floatCast|intToFloat|floatToInt|boolToInt|errSetCast)>"
+syn match zigBuiltinFn "\v\@(truncate|typeId|typeInfo|typeName|typeOf|atomicRmw|bytesToSlice|sliceToBytes)>"
+syn match zigBuiltinFn "\v\@(intToError|errorToInt|intToEnum|enumToInt|setAlignStack|handle|bitreverse|Vector)>"
+
+syn match zigDecNumber display "\<[0-9]\+\%(.[0-9]\+\)\=\%([eE][+-]\?[0-9]\+\)\="
+syn match zigHexNumber display "\<0x[a-fA-F0-9]\+\%([a-fA-F0-9]\+\%([pP][+-]\?[0-9]\+\)\?\)\="
+syn match zigOctNumber display "\<0o[0-7]\+"
+syn match zigBinNumber display "\<0b[01]\+\%(.[01]\+\%([eE][+-]\?[0-9]\+\)\?\)\="
+
+
+syn match zigCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/
+syn match zigCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/
+syn match zigCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=zigEscape,zigEscapeError,zigCharacterInvalid,zigCharacterInvalidUnicode
+syn match zigCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{6}\)\)'/ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigCharacterInvalid
+
+syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
+syn region zigCommentLineDoc start="////\@!" end="$" contains=zigTodo,@Spell
+
+" TODO: match only the first '\\' within the zigMultilineString as zigMultilineStringPrefix
+syn match zigMultilineStringPrefix display contained /c\?\\\\/
+syn region zigMultilineString start="c\?\\\\" end="$" contains=zigMultilineStringPrefix
+
+syn keyword zigTodo contained TODO
+
+syn match zigEscapeError display contained /\\./
+syn match zigEscape display contained /\\\([nrt\\'"]\|x\x\{2}\)/
+syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{6}\)/
+syn region zigString start=+c\?"+ skip=+\\\\\|\\"+ end=+"+ oneline contains=zigEscape,zigEscapeUnicode,zigEscapeError,@Spell
+
+hi def link zigDecNumber zigNumber
+hi def link zigHexNumber zigNumber
+hi def link zigOctNumber zigNumber
+hi def link zigBinNumber zigNumber
+
+hi def link zigBuiltinFn Function
+hi def link zigKeyword Keyword
+hi def link zigType Type
+hi def link zigCommentLine Comment
+hi def link zigCommentLineDoc SpecialComment
+hi def link zigTodo Todo
+hi def link zigString String
+hi def link zigMultilineString String
+hi def link zigMultilineStringContent String
+hi def link zigMultilineStringPrefix Comment
+hi def link zigCharacterInvalid Error
+hi def link zigCharacterInvalidUnicode zigCharacterInvalid
+hi def link zigCharacter Character
+hi def link zigEscape Special
+hi def link zigEscapeUnicode zigEscape
+hi def link zigEscapeError Error
+hi def link zigBoolean Boolean
+hi def link zigConstant Constant
+hi def link zigNumber Number
+hi def link zigArrowCharacter zigOperator
+hi def link zigOperator Operator
+hi def link zigStorage StorageClass
+hi def link zigStructure Structure
+hi def link zigStatement Statement
+hi def link zigConditional Conditional
+hi def link zigRepeat Repeat