aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--runtime/autoload/dist/ft.vim741
-rw-r--r--runtime/filetype.vim834
-rw-r--r--runtime/scripts.vim191
-rw-r--r--src/nvim/CMakeLists.txt4
-rw-r--r--src/nvim/edit.c3
-rw-r--r--src/nvim/fileio.c133
-rw-r--r--src/nvim/macros.h18
-rw-r--r--src/nvim/os/process.c2
-rw-r--r--src/nvim/po/CMakeLists.txt8
-rw-r--r--src/nvim/quickfix.c2
-rw-r--r--src/nvim/screen.c38
-rw-r--r--src/nvim/shada.c253
-rw-r--r--test/functional/shada/merging_spec.lua109
-rw-r--r--test/functional/shada/shada_spec.lua6
-rw-r--r--test/functional/ui/highlight_spec.lua36
-rw-r--r--test/helpers.lua2
-rw-r--r--third-party/CMakeLists.txt5
-rw-r--r--third-party/cmake/BuildLibtermkey.cmake24
-rw-r--r--third-party/cmake/BuildLuajit.cmake6
-rw-r--r--third-party/cmake/BuildLuv.cmake12
-rw-r--r--third-party/cmake/PatchLuv.cmake29
-rw-r--r--third-party/cmake/libtermkeyCMakeLists.txt34
-rw-r--r--third-party/patches/libtermkey-Add-support-for-Windows.patch170
-rw-r--r--third-party/patches/luv-Add-missing-definitions-for-MinGW.patch24
25 files changed, 1655 insertions, 1033 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b61743bc34..4b021ad6e7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,10 +5,6 @@ if(POLICY CMP0059)
cmake_policy(SET CMP0059 OLD) # Needed until cmake 2.8.12. #4389
endif()
-if(POLICY CMP0057)
- cmake_policy(SET CMP0057 NEW)
-endif()
-
# Point CMake at any custom modules we may ship
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
new file mode 100644
index 0000000000..2603c6822f
--- /dev/null
+++ b/runtime/autoload/dist/ft.vim
@@ -0,0 +1,741 @@
+" Vim functions for file type detection
+"
+" Maintainer: Bram Moolenaar <Bram@vim.org>
+" Last Change: 2017 Nov 11
+
+" These functions are moved here from runtime/filetype.vim to make startup
+" faster.
+
+" Line continuation is used here, remove 'C' from 'cpoptions'
+let s:cpo_save = &cpo
+set cpo&vim
+
+func dist#ft#Check_inp()
+ if getline(1) =~ '^\*'
+ setf abaqus
+ else
+ let n = 1
+ if line("$") > 500
+ let nmax = 500
+ else
+ let nmax = line("$")
+ endif
+ while n <= nmax
+ if getline(n) =~? "^header surface data"
+ setf trasys
+ break
+ endif
+ let n = n + 1
+ endwhile
+ endif
+endfunc
+
+" This function checks for the kind of assembly that is wanted by the user, or
+" can be detected from the first five lines of the file.
+func dist#ft#FTasm()
+ " make sure b:asmsyntax exists
+ if !exists("b:asmsyntax")
+ let b:asmsyntax = ""
+ endif
+
+ if b:asmsyntax == ""
+ call dist#ft#FTasmsyntax()
+ endif
+
+ " if b:asmsyntax still isn't set, default to asmsyntax or GNU
+ if b:asmsyntax == ""
+ if exists("g:asmsyntax")
+ let b:asmsyntax = g:asmsyntax
+ else
+ let b:asmsyntax = "asm"
+ endif
+ endif
+
+ exe "setf " . fnameescape(b:asmsyntax)
+endfunc
+
+func dist#ft#FTasmsyntax()
+ " see if file contains any asmsyntax=foo overrides. If so, change
+ " b:asmsyntax appropriately
+ let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
+ \" ".getline(5)." "
+ let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
+ if match != ''
+ let b:asmsyntax = match
+ elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
+ let b:asmsyntax = "vmasm"
+ endif
+endfunc
+
+" Check if one of the first five lines contains "VB_Name". In that case it is
+" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype.
+func dist#ft#FTVB(alt)
+ if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
+ setf vb
+ else
+ exe "setf " . a:alt
+ endif
+endfunc
+
+func dist#ft#FTbtm()
+ if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
+ setf dosbatch
+ else
+ setf btm
+ endif
+endfunc
+
+func dist#ft#BindzoneCheck(default)
+ if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
+ setf bindzone
+ elseif a:default != ''
+ exe 'setf ' . a:default
+ endif
+endfunc
+
+func dist#ft#FTlpc()
+ if exists("g:lpc_syntax_for_c")
+ let lnum = 1
+ while lnum <= 12
+ if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
+ setf lpc
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+ endif
+ setf c
+endfunc
+
+func dist#ft#FTheader()
+ if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
+ if exists("g:c_syntax_for_h")
+ setf objc
+ else
+ setf objcpp
+ endif
+ elseif exists("g:c_syntax_for_h")
+ setf c
+ elseif exists("g:ch_syntax_for_h")
+ setf ch
+ else
+ setf cpp
+ endif
+endfunc
+
+" This function checks if one of the first ten lines start with a '@'. In
+" that case it is probably a change file.
+" If the first line starts with # or ! it's probably a ch file.
+" If a line has "main", "include", "//" ir "/*" it's probably ch.
+" Otherwise CHILL is assumed.
+func dist#ft#FTchange()
+ let lnum = 1
+ while lnum <= 10
+ if getline(lnum)[0] == '@'
+ setf change
+ return
+ endif
+ if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
+ setf ch
+ return
+ endif
+ if getline(lnum) =~ "MODULE"
+ setf chill
+ return
+ endif
+ if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
+ setf ch
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+ setf chill
+endfunc
+
+func dist#ft#FTent()
+ " This function checks for valid cl syntax in the first five lines.
+ " Look for either an opening comment, '#', or a block start, '{".
+ " If not found, assume SGML.
+ let lnum = 1
+ while lnum < 6
+ let line = getline(lnum)
+ if line =~ '^\s*[#{]'
+ setf cl
+ return
+ elseif line !~ '^\s*$'
+ " Not a blank line, not a comment, and not a block start,
+ " so doesn't look like valid cl code.
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf dtd
+endfunc
+
+func dist#ft#EuphoriaCheck()
+ if exists('g:filetype_euphoria')
+ exe 'setf ' . g:filetype_euphoria
+ else
+ setf euphoria3
+ endif
+endfunc
+
+func dist#ft#DtraceCheck()
+ let lines = getline(1, min([line("$"), 100]))
+ if match(lines, '^module\>\|^import\>') > -1
+ " D files often start with a module and/or import statement.
+ setf d
+ elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
+ setf dtrace
+ else
+ setf d
+ endif
+endfunc
+
+func dist#ft#FTe()
+ if exists('g:filetype_euphoria')
+ exe 'setf ' . g:filetype_euphoria
+ else
+ let n = 1
+ while n < 100 && n < line("$")
+ if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
+ setf specman
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf eiffel
+ endif
+endfunc
+
+" Distinguish between HTML, XHTML and Django
+func dist#ft#FThtml()
+ let n = 1
+ while n < 10 && n < line("$")
+ if getline(n) =~ '\<DTD\s\+XHTML\s'
+ setf xhtml
+ return
+ endif
+ if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
+ setf htmldjango
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf html
+endfunc
+
+" Distinguish between standard IDL and MS-IDL
+func dist#ft#FTidl()
+ let n = 1
+ while n < 50 && n < line("$")
+ if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
+ setf msidl
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf idl
+endfunc
+
+" Distinguish between "default" and Cproto prototype file. */
+func dist#ft#ProtoCheck(default)
+ " Cproto files have a comment in the first line and a function prototype in
+ " the second line, it always ends in ";". Indent files may also have
+ " comments, thus we can't match comments to see the difference.
+ " IDL files can have a single ';' in the second line, require at least one
+ " chacter before the ';'.
+ if getline(2) =~ '.;$'
+ setf cpp
+ else
+ exe 'setf ' . a:default
+ endif
+endfunc
+
+func dist#ft#FTm()
+ let n = 1
+ let saw_comment = 0 " Whether we've seen a multiline comment leader.
+ while n < 100
+ let line = getline(n)
+ if line =~ '^\s*/\*'
+ " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
+ " it's either of them yet, but track this as a hint in case we don't see
+ " anything more definitive.
+ let saw_comment = 1
+ endif
+ if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
+ setf objc
+ return
+ endif
+ if line =~ '^\s*%'
+ setf matlab
+ return
+ endif
+ if line =~ '^\s*(\*'
+ setf mma
+ return
+ endif
+ if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
+ setf murphi
+ return
+ endif
+ let n = n + 1
+ endwhile
+
+ if saw_comment
+ " We didn't see anything definitive, but this looks like either Objective C
+ " or Murphi based on the comment leader. Assume the former as it is more
+ " common.
+ setf objc
+ elseif exists("g:filetype_m")
+ " Use user specified default filetype for .m
+ exe "setf " . g:filetype_m
+ else
+ " Default is matlab
+ setf matlab
+ endif
+endfunc
+
+func dist#ft#FTmms()
+ let n = 1
+ while n < 10
+ let line = getline(n)
+ if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
+ setf mmix
+ return
+ endif
+ if line =~ '^\s*#'
+ setf make
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf mmix
+endfunc
+
+" This function checks if one of the first five lines start with a dot. In
+" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
+func dist#ft#FTnroff()
+ if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
+ setf nroff
+ return 1
+ endif
+ return 0
+endfunc
+
+func dist#ft#FTmm()
+ let n = 1
+ while n < 10
+ let line = getline(n)
+ if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
+ setf objcpp
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf nroff
+endfunc
+
+func dist#ft#FTpl()
+ if exists("g:filetype_pl")
+ exe "setf " . g:filetype_pl
+ else
+ " recognize Prolog by specific text in the first non-empty line
+ " require a blank after the '%' because Perl uses "%list" and "%translate"
+ let l = getline(nextnonblank(1))
+ if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
+ setf prolog
+ else
+ setf perl
+ endif
+ endif
+endfunc
+
+func dist#ft#FTinc()
+ if exists("g:filetype_inc")
+ exe "setf " . g:filetype_inc
+ else
+ let lines = getline(1).getline(2).getline(3)
+ if lines =~? "perlscript"
+ setf aspperl
+ elseif lines =~ "<%"
+ setf aspvbs
+ elseif lines =~ "<?"
+ setf php
+ else
+ call dist#ft#FTasmsyntax()
+ if exists("b:asmsyntax")
+ exe "setf " . fnameescape(b:asmsyntax)
+ else
+ setf pov
+ endif
+ endif
+ endif
+endfunc
+
+func dist#ft#FTprogress_cweb()
+ if exists("g:filetype_w")
+ exe "setf " . g:filetype_w
+ return
+ endif
+ if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
+ setf progress
+ else
+ setf cweb
+ endif
+endfunc
+
+func dist#ft#FTprogress_asm()
+ if exists("g:filetype_i")
+ exe "setf " . g:filetype_i
+ return
+ endif
+ " This function checks for an assembly comment the first ten lines.
+ " If not found, assume Progress.
+ let lnum = 1
+ while lnum <= 10 && lnum < line('$')
+ let line = getline(lnum)
+ if line =~ '^\s*;' || line =~ '^\*'
+ call dist#ft#FTasm()
+ return
+ elseif line !~ '^\s*$' || line =~ '^/\*'
+ " Not an empty line: Doesn't look like valid assembly code.
+ " Or it looks like a Progress /* comment
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf progress
+endfunc
+
+func dist#ft#FTprogress_pascal()
+ if exists("g:filetype_p")
+ exe "setf " . g:filetype_p
+ return
+ endif
+ " This function checks for valid Pascal syntax in the first ten lines.
+ " Look for either an opening comment or a program start.
+ " If not found, assume Progress.
+ let lnum = 1
+ while lnum <= 10 && lnum < line('$')
+ let line = getline(lnum)
+ if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
+ \ || line =~ '^\s*{' || line =~ '^\s*(\*'
+ setf pascal
+ return
+ elseif line !~ '^\s*$' || line =~ '^/\*'
+ " Not an empty line: Doesn't look like valid Pascal code.
+ " Or it looks like a Progress /* comment
+ break
+ endif
+ let lnum = lnum + 1
+ endw
+ setf progress
+endfunc
+
+func dist#ft#FTr()
+ let max = line("$") > 50 ? 50 : line("$")
+
+ for n in range(1, max)
+ " Rebol is easy to recognize, check for that first
+ if getline(n) =~? '\<REBOL\>'
+ setf rebol
+ return
+ endif
+ endfor
+
+ for n in range(1, max)
+ " R has # comments
+ if getline(n) =~ '^\s*#'
+ setf r
+ return
+ endif
+ " Rexx has /* comments */
+ if getline(n) =~ '^\s*/\*'
+ setf rexx
+ return
+ endif
+ endfor
+
+ " Nothing recognized, use user default or assume Rexx
+ if exists("g:filetype_r")
+ exe "setf " . g:filetype_r
+ else
+ " Rexx used to be the default, but R appears to be much more popular.
+ setf r
+ endif
+endfunc
+
+func dist#ft#McSetf()
+ " Rely on the file to start with a comment.
+ " MS message text files use ';', Sendmail files use '#' or 'dnl'
+ for lnum in range(1, min([line("$"), 20]))
+ let line = getline(lnum)
+ if line =~ '^\s*\(#\|dnl\)'
+ setf m4 " Sendmail .mc file
+ return
+ elseif line =~ '^\s*;'
+ setf msmessages " MS Message text file
+ return
+ endif
+ endfor
+ setf m4 " Default: Sendmail .mc file
+endfunc
+
+" Called from filetype.vim and scripts.vim.
+func dist#ft#SetFileTypeSH(name)
+ if expand("<amatch>") =~ g:ft_ignore_pat
+ return
+ endif
+ if a:name =~ '\<csh\>'
+ " Some .sh scripts contain #!/bin/csh.
+ call dist#ft#SetFileTypeShell("csh")
+ return
+ elseif a:name =~ '\<tcsh\>'
+ " Some .sh scripts contain #!/bin/tcsh.
+ call dist#ft#SetFileTypeShell("tcsh")
+ return
+ elseif a:name =~ '\<zsh\>'
+ " Some .sh scripts contain #!/bin/zsh.
+ call dist#ft#SetFileTypeShell("zsh")
+ return
+ elseif a:name =~ '\<ksh\>'
+ let b:is_kornshell = 1
+ if exists("b:is_bash")
+ unlet b:is_bash
+ endif
+ if exists("b:is_sh")
+ unlet b:is_sh
+ endif
+ elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
+ let b:is_bash = 1
+ if exists("b:is_kornshell")
+ unlet b:is_kornshell
+ endif
+ if exists("b:is_sh")
+ unlet b:is_sh
+ endif
+ elseif a:name =~ '\<sh\>'
+ let b:is_sh = 1
+ if exists("b:is_kornshell")
+ unlet b:is_kornshell
+ endif
+ if exists("b:is_bash")
+ unlet b:is_bash
+ endif
+ endif
+ call dist#ft#SetFileTypeShell("sh")
+endfunc
+
+" For shell-like file types, check for an "exec" command hidden in a comment,
+" as used for Tcl.
+" Also called from scripts.vim, thus can't be local to this script.
+func dist#ft#SetFileTypeShell(name)
+ if expand("<amatch>") =~ g:ft_ignore_pat
+ return
+ endif
+ let l = 2
+ while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
+ " Skip empty and comment lines.
+ let l = l + 1
+ endwhile
+ if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
+ " Found an "exec" line after a comment with continuation
+ let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
+ if n =~ '\<tclsh\|\<wish'
+ setf tcl
+ return
+ endif
+ endif
+ exe "setf " . a:name
+endfunc
+
+func dist#ft#CSH()
+ if exists("g:filetype_csh")
+ call dist#ft#SetFileTypeShell(g:filetype_csh)
+ elseif &shell =~ "tcsh"
+ call dist#ft#SetFileTypeShell("tcsh")
+ else
+ call dist#ft#SetFileTypeShell("csh")
+ endif
+endfunc
+
+let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
+func dist#ft#FTRules()
+ let path = expand('<amatch>:p')
+ if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
+ setf udevrules
+ return
+ endif
+ if path =~ '^/etc/ufw/'
+ setf conf " Better than hog
+ return
+ endif
+ if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
+ setf javascript
+ return
+ endif
+ try
+ let config_lines = readfile('/etc/udev/udev.conf')
+ catch /^Vim\%((\a\+)\)\=:E484/
+ setf hog
+ return
+ endtry
+ let dir = expand('<amatch>:p:h')
+ for line in config_lines
+ if line =~ s:ft_rules_udev_rules_pattern
+ let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
+ if dir == udev_rules
+ setf udevrules
+ endif
+ break
+ endif
+ endfor
+ setf hog
+endfunc
+
+func dist#ft#SQL()
+ if exists("g:filetype_sql")
+ exe "setf " . g:filetype_sql
+ else
+ setf sql
+ endif
+endfunc
+
+" If the file has an extension of 't' and is in a directory 't' or 'xt' then
+" it is almost certainly a Perl test file.
+" If the first line starts with '#' and contains 'perl' it's probably a Perl
+" file.
+" (Slow test) If a file contains a 'use' statement then it is almost certainly
+" a Perl file.
+func dist#ft#FTperl()
+ let dirname = expand("%:p:h:t")
+ if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
+ setf perl
+ return 1
+ endif
+ if getline(1)[0] == '#' && getline(1) =~ 'perl'
+ setf perl
+ return 1
+ endif
+ if search('^use\s\s*\k', 'nc', 30)
+ setf perl
+ return 1
+ endif
+ return 0
+endfunc
+
+" Choose context, plaintex, or tex (LaTeX) based on these rules:
+" 1. Check the first line of the file for "%&<format>".
+" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
+" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
+func dist#ft#FTtex()
+ let firstline = getline(1)
+ if firstline =~ '^%&\s*\a\+'
+ let format = tolower(matchstr(firstline, '\a\+'))
+ let format = substitute(format, 'pdf', '', '')
+ if format == 'tex'
+ let format = 'latex'
+ elseif format == 'plaintex'
+ let format = 'plain'
+ endif
+ elseif expand('%') =~ 'tex/context/.*/.*.tex'
+ let format = 'context'
+ else
+ " Default value, may be changed later:
+ let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
+ " Save position, go to the top of the file, find first non-comment line.
+ let save_cursor = getpos('.')
+ call cursor(1,1)
+ let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
+ if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
+ let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
+ let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
+ let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
+ \ 'cnp', firstNC + 1000)
+ if kwline == 1 " lpat matched
+ let format = 'latex'
+ elseif kwline == 2 " cpat matched
+ let format = 'context'
+ endif " If neither matched, keep default set above.
+ " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
+ " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
+ " if cline > 0
+ " let format = 'context'
+ " endif
+ " if lline > 0 && (cline == 0 || cline > lline)
+ " let format = 'tex'
+ " endif
+ endif " firstNC
+ call setpos('.', save_cursor)
+ endif " firstline =~ '^%&\s*\a\+'
+
+ " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
+ if format == 'plain'
+ setf plaintex
+ elseif format == 'context'
+ setf context
+ else " probably LaTeX
+ setf tex
+ endif
+ return
+endfunc
+
+func dist#ft#FTxml()
+ let n = 1
+ while n < 100 && n < line("$")
+ let line = getline(n)
+ " DocBook 4 or DocBook 5.
+ let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
+ let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
+ if is_docbook4 || is_docbook5
+ let b:docbk_type = "xml"
+ if is_docbook5
+ let b:docbk_ver = 5
+ else
+ let b:docbk_ver = 4
+ endif
+ setf docbk
+ return
+ endif
+ if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
+ setf xbl
+ return
+ endif
+ let n += 1
+ endwhile
+ setf xml
+endfunc
+
+func dist#ft#FTy()
+ let n = 1
+ while n < 100 && n < line("$")
+ let line = getline(n)
+ if line =~ '^\s*%'
+ setf yacc
+ return
+ endif
+ if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
+ setf racc
+ return
+ endif
+ let n = n + 1
+ endwhile
+ setf yacc
+endfunc
+
+func dist#ft#Redif()
+ let lnum = 1
+ while lnum <= 5 && lnum < line('$')
+ if getline(lnum) =~ "^\ctemplate-type:"
+ setf redif
+ return
+ endif
+ let lnum = lnum + 1
+ endwhile
+endfunc
+
+
+" Restore 'cpoptions'
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 4e0f145c18..f8a29fa2b3 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -52,27 +52,7 @@ endfunc
au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help
" Abaqus or Trasys
-au BufNewFile,BufRead *.inp call s:Check_inp()
-
-func! s:Check_inp()
- if getline(1) =~ '^\*'
- setf abaqus
- else
- let n = 1
- if line("$") > 500
- let nmax = 500
- else
- let nmax = line("$")
- endif
- while n <= nmax
- if getline(n) =~? "^header surface data"
- setf trasys
- break
- endif
- let n = n + 1
- endwhile
- endif
-endfunc
+au BufNewFile,BufRead *.inp call dist#ft#Check_inp()
" A-A-P recipe
au BufNewFile,BufRead *.aap setf aap
@@ -170,44 +150,7 @@ au BufNewFile,BufRead */boot/grub/menu.lst,*/boot/grub/grub.conf,*/etc/grub.conf
" Assembly (all kinds)
" *.lst is not pure assembly, it has two extra columns (address, byte codes)
-au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call s:FTasm()
-
-" This function checks for the kind of assembly that is wanted by the user, or
-" can be detected from the first five lines of the file.
-func! s:FTasm()
- " make sure b:asmsyntax exists
- if !exists("b:asmsyntax")
- let b:asmsyntax = ""
- endif
-
- if b:asmsyntax == ""
- call s:FTasmsyntax()
- endif
-
- " if b:asmsyntax still isn't set, default to asmsyntax or GNU
- if b:asmsyntax == ""
- if exists("g:asmsyntax")
- let b:asmsyntax = g:asmsyntax
- else
- let b:asmsyntax = "asm"
- endif
- endif
-
- exe "setf " . fnameescape(b:asmsyntax)
-endfunc
-
-func! s:FTasmsyntax()
- " see if file contains any asmsyntax=foo overrides. If so, change
- " b:asmsyntax appropriately
- let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
- \" ".getline(5)." "
- let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
- if match != ''
- let b:asmsyntax = match
- elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
- let b:asmsyntax = "vmasm"
- endif
-endfunc
+au BufNewFile,BufRead *.asm,*.[sS],*.[aA],*.mac,*.lst call dist#ft#FTasm()
" Macro (VAX)
au BufNewFile,BufRead *.mar setf vmasm
@@ -237,17 +180,7 @@ au BufNewFile,BufRead *.awk setf awk
au BufNewFile,BufRead *.mch,*.ref,*.imp setf b
" BASIC or Visual Basic
-au BufNewFile,BufRead *.bas call s:FTVB("basic")
-
-" Check if one of the first five lines contains "VB_Name". In that case it is
-" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype.
-func! s:FTVB(alt)
- if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
- setf vb
- else
- exe "setf " . a:alt
- endif
-endfunc
+au BufNewFile,BufRead *.bas call dist#ft#FTVB("basic")
" Visual Basic Script (close to Visual Basic) or Visual Basic .NET
au BufNewFile,BufRead *.vb,*.vbs,*.dsm,*.ctl setf vb
@@ -265,14 +198,7 @@ au BufNewFile,BufRead *.cmd
\ if getline(1) =~ '^/\*' | setf rexx | else | setf dosbatch | endif
" Batch file for 4DOS
-au BufNewFile,BufRead *.btm call s:FTbtm()
-func! s:FTbtm()
- if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
- setf dosbatch
- else
- setf btm
- endif
-endfunc
+au BufNewFile,BufRead *.btm call dist#ft#FTbtm()
" BC calculator
au BufNewFile,BufRead *.bc setf bc
@@ -292,15 +218,7 @@ au BufNewFile,BufRead named*.conf,rndc*.conf,rndc*.key setf named
" BIND zone
au BufNewFile,BufRead named.root setf bindzone
-au BufNewFile,BufRead *.db call s:BindzoneCheck('')
-
-func! s:BindzoneCheck(default)
- if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
- setf bindzone
- elseif a:default != ''
- exe 'setf ' . a:default
- endif
-endfunc
+au BufNewFile,BufRead *.db call dist#ft#BindzoneCheck('')
" Blank
au BufNewFile,BufRead *.bl setf blank
@@ -309,27 +227,14 @@ au BufNewFile,BufRead *.bl setf blank
au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml
" Bazel (http://bazel.io)
-autocmd BufRead,BufNewFile *.bzl,WORKSPACE setfiletype bzl
+autocmd BufRead,BufNewFile *.bzl,WORKSPACE setf bzl
if has("fname_case")
- autocmd BufRead,BufNewFile BUILD setfiletype bzl
+ " There is another check for BUILD further below.
+ autocmd BufRead,BufNewFile BUILD setf bzl
endif
" C or lpc
-au BufNewFile,BufRead *.c call s:FTlpc()
-
-func! s:FTlpc()
- if exists("g:lpc_syntax_for_c")
- let lnum = 1
- while lnum <= 12
- if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
- setf lpc
- return
- endif
- let lnum = lnum + 1
- endwhile
- endif
- setf c
-endfunc
+au BufNewFile,BufRead *.c call dist#ft#FTlpc()
" Calendar
au BufNewFile,BufRead calendar setf calendar
@@ -383,23 +288,7 @@ endif
" .h files can be C, Ch C++, ObjC or ObjC++.
" Set c_syntax_for_h if you want C, ch_syntax_for_h if you want Ch. ObjC is
" detected automatically.
-au BufNewFile,BufRead *.h call s:FTheader()
-
-func! s:FTheader()
- if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
- if exists("g:c_syntax_for_h")
- setf objc
- else
- setf objcpp
- endif
- elseif exists("g:c_syntax_for_h")
- setf c
- elseif exists("g:ch_syntax_for_h")
- setf ch
- else
- setf cpp
- endif
-endfunc
+au BufNewFile,BufRead *.h call dist#ft#FTheader()
" Ch (CHscript)
au BufNewFile,BufRead *.chf setf ch
@@ -433,36 +322,7 @@ au BufNewFile,BufRead NEWS
au BufNewFile,BufRead *..ch setf chill
" Changes for WEB and CWEB or CHILL
-au BufNewFile,BufRead *.ch call s:FTchange()
-
-" This function checks if one of the first ten lines start with a '@'. In
-" that case it is probably a change file.
-" If the first line starts with # or ! it's probably a ch file.
-" If a line has "main", "include", "//" ir "/*" it's probably ch.
-" Otherwise CHILL is assumed.
-func! s:FTchange()
- let lnum = 1
- while lnum <= 10
- if getline(lnum)[0] == '@'
- setf change
- return
- endif
- if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
- setf ch
- return
- endif
- if getline(lnum) =~ "MODULE"
- setf chill
- return
- endif
- if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
- setf ch
- return
- endif
- let lnum = lnum + 1
- endwhile
- setf chill
-endfunc
+au BufNewFile,BufRead *.ch call dist#ft#FTchange()
" ChordPro
au BufNewFile,BufRead *.chopro,*.crd,*.cho,*.crdpro,*.chordpro setf chordpro
@@ -474,27 +334,7 @@ au BufNewFile,BufRead *.dcl,*.icl setf clean
au BufNewFile,BufRead *.eni setf cl
" Clever or dtd
-au BufNewFile,BufRead *.ent call s:FTent()
-
-func! s:FTent()
- " This function checks for valid cl syntax in the first five lines.
- " Look for either an opening comment, '#', or a block start, '{".
- " If not found, assume SGML.
- let lnum = 1
- while lnum < 6
- let line = getline(lnum)
- if line =~ '^\s*[#{]'
- setf cl
- return
- elseif line !~ '^\s*$'
- " Not a blank line, not a comment, and not a block start,
- " so doesn't look like valid cl code.
- break
- endif
- let lnum = lnum + 1
- endw
- setf dtd
-endfunc
+au BufNewFile,BufRead *.ent call dist#ft#FTent()
" Clipper (or FoxPro; could also be eviews)
au BufNewFile,BufRead *.prg
@@ -549,19 +389,11 @@ au BufNewFile,BufRead *enlightenment/*.cfg setf c
au BufNewFile,BufRead *Eterm/*.cfg setf eterm
" Euphoria 3 or 4
-au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call s:EuphoriaCheck()
+au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call dist#ft#EuphoriaCheck()
if has("fname_case")
- au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call s:EuphoriaCheck()
+ au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call dist#ft#EuphoriaCheck()
endif
-func! s:EuphoriaCheck()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- setf euphoria3
- endif
-endfunc
-
" Lynx config files
au BufNewFile,BufRead lynx.cfg setf lynx
@@ -606,19 +438,7 @@ au BufNewFile,BufRead */etc/dnsmasq.conf setf dnsmasq
au BufNewFile,BufRead *.desc setf desc
" the D language or dtrace
-au BufNewFile,BufRead *.d call s:DtraceCheck()
-
-func! s:DtraceCheck()
- let lines = getline(1, min([line("$"), 100]))
- if match(lines, '^module\>\|^import\>') > -1
- " D files often start with a module and/or import statement.
- setf d
- elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
- setf dtrace
- else
- setf d
- endif
-endfunc
+au BufNewFile,BufRead *.d call dist#ft#DtraceCheck()
" Desktop files
au BufNewFile,BufRead *.desktop,.directory setf desktop
@@ -650,7 +470,7 @@ au BufNewFile,BufRead *.rul
\ endif
" DCL (Digital Command Language - vms) or DNS zone file
-au BufNewFile,BufRead *.com call s:BindzoneCheck('dcl')
+au BufNewFile,BufRead *.com call dist#ft#BindzoneCheck('dcl')
" DOT
au BufNewFile,BufRead *.dot setf dot
@@ -698,27 +518,11 @@ au BufNewFile,BufRead .editorconfig setf dosini
au BufNewFile,BufRead *.ecd setf ecd
" Eiffel or Specman or Euphoria
-au BufNewFile,BufRead *.e,*.E call s:FTe()
+au BufNewFile,BufRead *.e,*.E call dist#ft#FTe()
" Elinks configuration
au BufNewFile,BufRead */etc/elinks.conf,*/.elinks/elinks.conf setf elinks
-func! s:FTe()
- if exists('g:filetype_euphoria')
- exe 'setf ' . g:filetype_euphoria
- else
- let n = 1
- while n < 100 && n < line("$")
- if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
- setf specman
- return
- endif
- let n = n + 1
- endwhile
- setf eiffel
- endif
-endfunc
-
" ERicsson LANGuage; Yaws is erlang too
au BufNewFile,BufRead *.erl,*.hrl,*.yaws setf erlang
@@ -887,24 +691,7 @@ au BufNewFile,BufRead *.hex,*.h32 setf hex
au BufNewFile,BufRead *.t.html setf tilde
" HTML (.shtml and .stm for server side)
-au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call s:FThtml()
-
-" Distinguish between HTML, XHTML and Django
-func! s:FThtml()
- let n = 1
- while n < 10 && n < line("$")
- if getline(n) =~ '\<DTD\s\+XHTML\s'
- setf xhtml
- return
- endif
- if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
- setf htmldjango
- return
- endif
- let n = n + 1
- endwhile
- setf html
-endfunc
+au BufNewFile,BufRead *.html,*.htm,*.shtml,*.stm call dist#ft#FThtml()
" HTML with Ruby - eRuby
au BufNewFile,BufRead *.erb,*.rhtml setf eruby
@@ -931,20 +718,7 @@ au BufNewFile,BufRead *.htt,*.htb setf httest
au BufNewFile,BufRead *.icn setf icon
" IDL (Interface Description Language)
-au BufNewFile,BufRead *.idl call s:FTidl()
-
-" Distinguish between standard IDL and MS-IDL
-func! s:FTidl()
- let n = 1
- while n < 50 && n < line("$")
- if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
- setf msidl
- return
- endif
- let n = n + 1
- endwhile
- setf idl
-endfunc
+au BufNewFile,BufRead *.idl call dist#ft#FTidl()
" Microsoft IDL (Interface Description Language) Also *.idl
" MOF = WMI (Windows Management Instrumentation) Managed Object Format
@@ -955,25 +729,10 @@ au BufNewFile,BufRead */.icewm/menu setf icemenu
" Indent profile (must come before IDL *.pro!)
au BufNewFile,BufRead .indent.pro setf indent
-au BufNewFile,BufRead indent.pro call s:ProtoCheck('indent')
+au BufNewFile,BufRead indent.pro call dist#ft#ProtoCheck('indent')
" IDL (Interactive Data Language)
-au BufNewFile,BufRead *.pro call s:ProtoCheck('idlang')
-
-" Distinguish between "default" and Cproto prototype file. */
-func! s:ProtoCheck(default)
- " Cproto files have a comment in the first line and a function prototype in
- " the second line, it always ends in ";". Indent files may also have
- " comments, thus we can't match comments to see the difference.
- " IDL files can have a single ';' in the second line, require at least one
- " chacter before the ';'.
- if getline(2) =~ '.;$'
- setf cpp
- else
- exe 'setf ' . a:default
- endif
-endfunc
-
+au BufNewFile,BufRead *.pro call dist#ft#ProtoCheck('idlang')
" Indent RC
au BufNewFile,BufRead indentrc setf indent
@@ -1187,51 +946,7 @@ au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
au BufNewFile,BufRead *.mason,*.mhtml,*.comp setf mason
" Mathematica, Matlab, Murphi or Objective C
-au BufNewFile,BufRead *.m call s:FTm()
-
-func! s:FTm()
- let n = 1
- let saw_comment = 0 " Whether we've seen a multiline comment leader.
- while n < 100
- let line = getline(n)
- if line =~ '^\s*/\*'
- " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
- " it's either of them yet, but track this as a hint in case we don't see
- " anything more definitive.
- let saw_comment = 1
- endif
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
- setf objc
- return
- endif
- if line =~ '^\s*%'
- setf matlab
- return
- endif
- if line =~ '^\s*(\*'
- setf mma
- return
- endif
- if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
- setf murphi
- return
- endif
- let n = n + 1
- endwhile
-
- if saw_comment
- " We didn't see anything definitive, but this looks like either Objective C
- " or Murphi based on the comment leader. Assume the former as it is more
- " common.
- setf objc
- elseif exists("g:filetype_m")
- " Use user specified default filetype for .m
- exe "setf " . g:filetype_m
- else
- " Default is matlab
- setf matlab
- endif
-endfunc
+au BufNewFile,BufRead *.m call dist#ft#FTm()
" Mathematica notebook
au BufNewFile,BufRead *.nb setf mma
@@ -1261,29 +976,11 @@ au BufNewFile,BufRead *.mgl setf mgl
au BufNewFile,BufRead *.mix,*.mixal setf mix
" MMIX or VMS makefile
-au BufNewFile,BufRead *.mms call s:FTmms()
+au BufNewFile,BufRead *.mms call dist#ft#FTmms()
" Symbian meta-makefile definition (MMP)
au BufNewFile,BufRead *.mmp setf mmp
-func! s:FTmms()
- let n = 1
- while n < 10
- let line = getline(n)
- if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
- setf mmix
- return
- endif
- if line =~ '^\s*#'
- setf make
- return
- endif
- let n = n + 1
- endwhile
- setf mmix
-endfunc
-
-
" Modsim III (or LambdaProlog)
au BufNewFile,BufRead *.mod
\ if getline(1) =~ '\<module\>' |
@@ -1367,33 +1064,10 @@ au BufNewFile,BufRead *.me
\ setf nroff |
\ endif
au BufNewFile,BufRead *.tr,*.nr,*.roff,*.tmac,*.mom setf nroff
-au BufNewFile,BufRead *.[1-9] call s:FTnroff()
-
-" This function checks if one of the first five lines start with a dot. In
-" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
-func! s:FTnroff()
- if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
- setf nroff
- return 1
- endif
- return 0
-endfunc
+au BufNewFile,BufRead *.[1-9] call dist#ft#FTnroff()
" Nroff or Objective C++
-au BufNewFile,BufRead *.mm call s:FTmm()
-
-func! s:FTmm()
- let n = 1
- while n < 10
- let line = getline(n)
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
- setf objcpp
- return
- endif
- let n = n + 1
- endwhile
- setf nroff
-endfunc
+au BufNewFile,BufRead *.mm call dist#ft#FTmm()
" Not Quite C
au BufNewFile,BufRead *.nqc setf nqc
@@ -1448,28 +1122,13 @@ au BufNewFile,BufRead *.pcmk setf pcmk
" Perl
if has("fname_case")
- au BufNewFile,BufRead *.pl,*.PL call s:FTpl()
+ au BufNewFile,BufRead *.pl,*.PL call dist#ft#FTpl()
else
- au BufNewFile,BufRead *.pl call s:FTpl()
+ au BufNewFile,BufRead *.pl call dist#ft#FTpl()
endif
au BufNewFile,BufRead *.plx,*.al,*.psgi setf perl
au BufNewFile,BufRead *.p6,*.pm6,*.pl6 setf perl6
-func! s:FTpl()
- if exists("g:filetype_pl")
- exe "setf " . g:filetype_pl
- else
- " recognize Prolog by specific text in the first non-empty line
- " require a blank after the '%' because Perl uses "%list" and "%translate"
- let l = getline(nextnonblank(1))
- if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
- setf prolog
- else
- setf perl
- endif
- endif
-endfunc
-
" Perl, XPM or XPM2
au BufNewFile,BufRead *.pm
\ if getline(1) =~ "XPM2" |
@@ -1482,7 +1141,7 @@ au BufNewFile,BufRead *.pm
" Perl POD
au BufNewFile,BufRead *.pod setf pod
-au BufNewFile,BufRead *.pod6 setf pod6
+au BufNewFile,BufRead *.pod6 setf pod6
" Php, php3, php4, etc.
" Also Phtml (was used for PHP 2 in the past)
@@ -1532,29 +1191,7 @@ au BufNewFile,BufRead *.pov setf pov
au BufNewFile,BufRead .povrayrc setf povini
" Povray, PHP or assembly
-au BufNewFile,BufRead *.inc call s:FTinc()
-
-func! s:FTinc()
- if exists("g:filetype_inc")
- exe "setf " . g:filetype_inc
- else
- let lines = getline(1).getline(2).getline(3)
- if lines =~? "perlscript"
- setf aspperl
- elseif lines =~ "<%"
- setf aspvbs
- elseif lines =~ "<?"
- setf php
- else
- call s:FTasmsyntax()
- if exists("b:asmsyntax")
- exe "setf " . fnameescape(b:asmsyntax)
- else
- setf pov
- endif
- endif
- endif
-endfunc
+au BufNewFile,BufRead *.inc call dist#ft#FTinc()
" Printcap and Termcap
au BufNewFile,BufRead *printcap
@@ -1583,74 +1220,13 @@ au BufNewFile,BufRead *.action setf privoxy
au BufNewFile,BufRead .procmail,.procmailrc setf procmail
" Progress or CWEB
-au BufNewFile,BufRead *.w call s:FTprogress_cweb()
-
-func! s:FTprogress_cweb()
- if exists("g:filetype_w")
- exe "setf " . g:filetype_w
- return
- endif
- if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
- setf progress
- else
- setf cweb
- endif
-endfunc
+au BufNewFile,BufRead *.w call dist#ft#FTprogress_cweb()
" Progress or assembly
-au BufNewFile,BufRead *.i call s:FTprogress_asm()
-
-func! s:FTprogress_asm()
- if exists("g:filetype_i")
- exe "setf " . g:filetype_i
- return
- endif
- " This function checks for an assembly comment the first ten lines.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ '^\s*;' || line =~ '^\*'
- call s:FTasm()
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid assembly code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
+au BufNewFile,BufRead *.i call dist#ft#FTprogress_asm()
" Progress or Pascal
-au BufNewFile,BufRead *.p call s:FTprogress_pascal()
-
-func! s:FTprogress_pascal()
- if exists("g:filetype_p")
- exe "setf " . g:filetype_p
- return
- endif
- " This function checks for valid Pascal syntax in the first ten lines.
- " Look for either an opening comment or a program start.
- " If not found, assume Progress.
- let lnum = 1
- while lnum <= 10 && lnum < line('$')
- let line = getline(lnum)
- if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
- \ || line =~ '^\s*{' || line =~ '^\s*(\*'
- setf pascal
- return
- elseif line !~ '^\s*$' || line =~ '^/\*'
- " Not an empty line: Doesn't look like valid Pascal code.
- " Or it looks like a Progress /* comment
- break
- endif
- let lnum = lnum + 1
- endw
- setf progress
-endfunc
-
+au BufNewFile,BufRead *.p call dist#ft#FTprogress_pascal()
" Software Distributor Product Specification File (POSIX 1387.2-1995)
au BufNewFile,BufRead *.psf setf psf
@@ -1736,40 +1312,7 @@ else
endif
" Rexx, Rebol or R
-au BufNewFile,BufRead *.r,*.R call s:FTr()
-
-func! s:FTr()
- let max = line("$") > 50 ? 50 : line("$")
-
- for n in range(1, max)
- " Rebol is easy to recognize, check for that first
- if getline(n) =~? '\<REBOL\>'
- setf rebol
- return
- endif
- endfor
-
- for n in range(1, max)
- " R has # comments
- if getline(n) =~ '^\s*#'
- setf r
- return
- endif
- " Rexx has /* comments */
- if getline(n) =~ '^\s*/\*'
- setf rexx
- return
- endif
- endfor
-
- " Nothing recognized, use user default or assume Rexx
- if exists("g:filetype_r")
- exe "setf " . g:filetype_r
- else
- " Rexx used to be the default, but R appears to be much more popular.
- setf r
- endif
-endfunc
+au BufNewFile,BufRead *.r,*.R call dist#ft#FTr()
" Remind
au BufNewFile,BufRead .reminders,*.remind,*.rem setf remind
@@ -1865,23 +1408,7 @@ au BufNewFile,BufRead *.siv setf sieve
au BufNewFile,BufRead sendmail.cf setf sm
" Sendmail .mc files are actually m4. Could also be MS Message text file.
-au BufNewFile,BufRead *.mc call s:McSetf()
-
-func! s:McSetf()
- " Rely on the file to start with a comment.
- " MS message text files use ';', Sendmail files use '#' or 'dnl'
- for lnum in range(1, min([line("$"), 20]))
- let line = getline(lnum)
- if line =~ '^\s*\(#\|dnl\)'
- setf m4 " Sendmail .mc file
- return
- elseif line =~ '^\s*;'
- setf msmessages " MS Message text file
- return
- endif
- endfor
- setf m4 " Default: Sendmail .mc file
-endfunc
+au BufNewFile,BufRead *.mc call dist#ft#McSetf()
" Services
au BufNewFile,BufRead */etc/services setf services
@@ -1922,101 +1449,23 @@ au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog')
" Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc.
" Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts
-au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD* call SetFileTypeSH("bash")
-au BufNewFile,BufRead .kshrc*,*.ksh call SetFileTypeSH("ksh")
-au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call SetFileTypeSH(getline(1))
+au BufNewFile,BufRead .bashrc*,bashrc,bash.bashrc,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,*.bash,*/{,.}bash[_-]completion{,.d,.sh}{,/*},*.ebuild,*.eclass,PKGBUILD* call dist#ft#SetFileTypeSH("bash")
+au BufNewFile,BufRead .kshrc*,*.ksh call dist#ft#SetFileTypeSH("ksh")
+au BufNewFile,BufRead */etc/profile,.profile*,*.sh,*.env call dist#ft#SetFileTypeSH(getline(1))
" Shell script (Arch Linux) or PHP file (Drupal)
au BufNewFile,BufRead *.install
\ if getline(1) =~ '<?php' |
\ setf php |
\ else |
- \ call SetFileTypeSH("bash") |
+ \ call dist#ft#SetFileTypeSH("bash") |
\ endif
-" Also called from scripts.vim.
-func! SetFileTypeSH(name)
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- if a:name =~ '\<csh\>'
- " Some .sh scripts contain #!/bin/csh.
- call SetFileTypeShell("csh")
- return
- elseif a:name =~ '\<tcsh\>'
- " Some .sh scripts contain #!/bin/tcsh.
- call SetFileTypeShell("tcsh")
- return
- elseif a:name =~ '\<zsh\>'
- " Some .sh scripts contain #!/bin/zsh.
- call SetFileTypeShell("zsh")
- return
- elseif a:name =~ '\<ksh\>'
- let b:is_kornshell = 1
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
- let b:is_bash = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_sh")
- unlet b:is_sh
- endif
- elseif a:name =~ '\<sh\>'
- let b:is_sh = 1
- if exists("b:is_kornshell")
- unlet b:is_kornshell
- endif
- if exists("b:is_bash")
- unlet b:is_bash
- endif
- endif
- call SetFileTypeShell("sh")
-endfunc
-
-" For shell-like file types, check for an "exec" command hidden in a comment,
-" as used for Tcl.
-" Also called from scripts.vim, thus can't be local to this script.
-func! SetFileTypeShell(name)
- if expand("<amatch>") =~ g:ft_ignore_pat
- return
- endif
- let l = 2
- while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
- " Skip empty and comment lines.
- let l = l + 1
- endwhile
- if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
- " Found an "exec" line after a comment with continuation
- let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
- if n =~ '\<tclsh\|\<wish'
- setf tcl
- return
- endif
- endif
- exe "setf " . a:name
-endfunc
-
" tcsh scripts
-au BufNewFile,BufRead .tcshrc*,*.tcsh,tcsh.tcshrc,tcsh.login call SetFileTypeShell("tcsh")
+au BufNewFile,BufRead .tcshrc*,*.tcsh,tcsh.tcshrc,tcsh.login call dist#ft#SetFileTypeShell("tcsh")
" csh scripts, but might also be tcsh scripts (on some systems csh is tcsh)
-au BufNewFile,BufRead .login*,.cshrc*,csh.cshrc,csh.login,csh.logout,*.csh,.alias call s:CSH()
-
-func! s:CSH()
- if exists("g:filetype_csh")
- call SetFileTypeShell(g:filetype_csh)
- elseif &shell =~ "tcsh"
- call SetFileTypeShell("tcsh")
- else
- call SetFileTypeShell("csh")
- endif
-endfunc
+au BufNewFile,BufRead .login*,.cshrc*,csh.cshrc,csh.login,csh.logout,*.csh,.alias call dist#ft#CSH()
" Z-Shell script
au BufNewFile,BufRead .zprofile,*/etc/zprofile,.zfbfmarks setf zsh
@@ -2087,42 +1536,7 @@ au BufNewFile,BufRead *.mib,*.my setf mib
" Snort Configuration
au BufNewFile,BufRead *.hog,snort.conf,vision.conf setf hog
-au BufNewFile,BufRead *.rules call s:FTRules()
-
-let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
-func! s:FTRules()
- let path = expand('<amatch>:p')
- if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
- setf udevrules
- return
- endif
- if path =~ '^/etc/ufw/'
- setf conf " Better than hog
- return
- endif
- if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
- setf javascript
- return
- endif
- try
- let config_lines = readfile('/etc/udev/udev.conf')
- catch /^Vim\%((\a\+)\)\=:E484/
- setf hog
- return
- endtry
- let dir = expand('<amatch>:p:h')
- for line in config_lines
- if line =~ s:ft_rules_udev_rules_pattern
- let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
- if dir == udev_rules
- setf udevrules
- endif
- break
- endif
- endfor
- setf hog
-endfunc
-
+au BufNewFile,BufRead *.rules call dist#ft#FTRules()
" Spec (Linux RPM)
au BufNewFile,BufRead *.spec setf spec
@@ -2146,15 +1560,7 @@ au BufNewFile,BufRead squid.conf setf squid
au BufNewFile,BufRead *.tyb,*.typ,*.tyc,*.pkb,*.pks setf sql
" SQL
-au BufNewFile,BufRead *.sql call s:SQL()
-
-func! s:SQL()
- if exists("g:filetype_sql")
- exe "setf " . g:filetype_sql
- else
- setf sql
- endif
-endfunc
+au BufNewFile,BufRead *.sql call dist#ft#SQL()
" SQLJ
au BufNewFile,BufRead *.sqlj setf sqlj
@@ -2201,32 +1607,9 @@ au BufNewFile,BufRead */etc/sudoers,sudoers.tmp setf sudoers
" SVG (Scalable Vector Graphics)
au BufNewFile,BufRead *.svg setf svg
-" If the file has an extension of 't' and is in a directory 't' or 'xt' then
-" it is almost certainly a Perl test file.
-" If the first line starts with '#' and contains 'perl' it's probably a Perl
-" file.
-" (Slow test) If a file contains a 'use' statement then it is almost certainly
-" a Perl file.
-func! s:FTperl()
- let dirname = expand("%:p:h:t")
- if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
- setf perl
- return 1
- endif
- if getline(1)[0] == '#' && getline(1) =~ 'perl'
- setf perl
- return 1
- endif
- if search('^use\s\s*\k', 'nc', 30)
- setf perl
- return 1
- endif
- return 0
-endfunc
-
" Tads (or Nroff or Perl test file)
au BufNewFile,BufRead *.t
- \ if !s:FTnroff() && !s:FTperl() | setf tads | endif
+ \ if !dist#ft#FTnroff() && !dist#ft#FTperl() | setf tads | endif
" Tags
au BufNewFile,BufRead tags setf tags
@@ -2255,63 +1638,7 @@ au BufNewFile,BufRead *.ti setf terminfo
" TeX
au BufNewFile,BufRead *.latex,*.sty,*.dtx,*.ltx,*.bbl setf tex
-au BufNewFile,BufRead *.tex call s:FTtex()
-
-" Choose context, plaintex, or tex (LaTeX) based on these rules:
-" 1. Check the first line of the file for "%&<format>".
-" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
-" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
-func! s:FTtex()
- let firstline = getline(1)
- if firstline =~ '^%&\s*\a\+'
- let format = tolower(matchstr(firstline, '\a\+'))
- let format = substitute(format, 'pdf', '', '')
- if format == 'tex'
- let format = 'latex'
- elseif format == 'plaintex'
- let format = 'plain'
- endif
- elseif expand('%') =~ 'tex/context/.*/.*.tex'
- let format = 'context'
- else
- " Default value, may be changed later:
- let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
- " Save position, go to the top of the file, find first non-comment line.
- let save_cursor = getpos('.')
- call cursor(1,1)
- let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
- if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
- let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
- let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
- let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
- \ 'cnp', firstNC + 1000)
- if kwline == 1 " lpat matched
- let format = 'latex'
- elseif kwline == 2 " cpat matched
- let format = 'context'
- endif " If neither matched, keep default set above.
- " let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
- " let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
- " if cline > 0
- " let format = 'context'
- " endif
- " if lline > 0 && (cline == 0 || cline > lline)
- " let format = 'tex'
- " endif
- endif " firstNC
- call setpos('.', save_cursor)
- endif " firstline =~ '^%&\s*\a\+'
-
- " Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
- if format == 'plain'
- setf plaintex
- elseif format == 'context'
- setf context
- else " probably LaTeX
- setf tex
- endif
- return
-endfunc
+au BufNewFile,BufRead *.tex call dist#ft#FTtex()
" ConTeXt
au BufNewFile,BufRead *.mkii,*.mkiv,*.mkvi setf context
@@ -2412,7 +1739,7 @@ au BufRead,BufNewFile *.hw,*.module,*.pkg
\ endif
" Visual Basic (also uses *.bas) or FORM
-au BufNewFile,BufRead *.frm call s:FTVB("form")
+au BufNewFile,BufRead *.frm call dist#ft#FTVB("form")
" SaxBasic is close to Visual Basic
au BufNewFile,BufRead *.sba setf vb
@@ -2502,36 +1829,10 @@ au BufNewFile,BufRead .Xdefaults,.Xpdefaults,.Xresources,xdm-config,*.ad setf xd
" Xmath
au BufNewFile,BufRead *.msc,*.msf setf xmath
au BufNewFile,BufRead *.ms
- \ if !s:FTnroff() | setf xmath | endif
+ \ if !dist#ft#FTnroff() | setf xmath | endif
" XML specific variants: docbk and xbl
-au BufNewFile,BufRead *.xml call s:FTxml()
-
-func! s:FTxml()
- let n = 1
- while n < 100 && n < line("$")
- let line = getline(n)
- " DocBook 4 or DocBook 5.
- let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
- let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
- if is_docbook4 || is_docbook5
- let b:docbk_type = "xml"
- if is_docbook5
- let b:docbk_ver = 5
- else
- let b:docbk_ver = 4
- endif
- setf docbk
- return
- endif
- if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
- setf xbl
- return
- endif
- let n += 1
- endwhile
- setf xml
-endfunc
+au BufNewFile,BufRead *.xml call dist#ft#FTxml()
" XMI (holding UML models) is also XML
au BufNewFile,BufRead *.xmi setf xml
@@ -2574,25 +1875,7 @@ au BufNewFile,BufRead *.xsl,*.xslt setf xslt
au BufNewFile,BufRead *.yy,*.yxx,*.y++ setf yacc
" Yacc or racc
-au BufNewFile,BufRead *.y call s:FTy()
-
-func! s:FTy()
- let n = 1
- while n < 100 && n < line("$")
- let line = getline(n)
- if line =~ '^\s*%'
- setf yacc
- return
- endif
- if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
- setf racc
- return
- endif
- let n = n + 1
- endwhile
- setf yacc
-endfunc
-
+au BufNewFile,BufRead *.y call dist#ft#FTy()
" Yaml
au BufNewFile,BufRead *.yaml,*.yml setf yaml
@@ -2608,9 +1891,9 @@ au BufNewFile,BufRead *.zut setf zimbutempl
" Zope
" dtml (zope dynamic template markup language), pt (zope page template),
" cpt (zope form controller page template)
-au BufNewFile,BufRead *.dtml,*.pt,*.cpt call s:FThtml()
+au BufNewFile,BufRead *.dtml,*.pt,*.cpt call dist#ft#FThtml()
" zsql (zope sql method)
-au BufNewFile,BufRead *.zsql call s:SQL()
+au BufNewFile,BufRead *.zsql call dist#ft#SQL()
" Z80 assembler asz80
au BufNewFile,BufRead *.z8a setf z8a
@@ -2652,6 +1935,11 @@ au BufNewFile,BufRead *asterisk*/*voicemail.conf* call s:StarSetf('asteriskvm')
" Bazaar version control
au BufNewFile,BufRead bzr_log.* setf bzr
+" Bazel build file
+if !has("fname_case")
+ au BufNewFile,BufRead BUILD setf bzl
+endif
+
" BIND zone
au BufNewFile,BufRead */named/db.*,*/bind/db.* call s:StarSetf('bindzone')
@@ -2759,17 +2047,7 @@ au BufNewFile,BufRead *termcap*
" ReDIF
" Only used when the .rdf file was not detected to be XML.
-au BufRead,BufNewFile *.rdf call s:Redif()
-func! s:Redif()
- let lnum = 1
- while lnum <= 5 && lnum < line('$')
- if getline(lnum) =~ "^\ctemplate-type:"
- setf redif
- return
- endif
- let lnum = lnum + 1
- endwhile
-endfunc
+au BufRead,BufNewFile *.rdf call dist#ft#Redif()
" Remind
au BufNewFile,BufRead .reminders* call s:StarSetf('remind')
diff --git a/runtime/scripts.vim b/runtime/scripts.vim
index 63bf9efcf9..18263e2842 100644
--- a/runtime/scripts.vim
+++ b/runtime/scripts.vim
@@ -1,11 +1,15 @@
" Vim support file to detect file types in scripts
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last change: 2017 Aug 27
+" Last change: 2017 Nov 11
" This file is called by an autocommand for every file that has just been
" loaded into a buffer. It checks if the type of file can be recognized by
" the file contents. The autocommand is in $VIMRUNTIME/filetype.vim.
+"
+" Note that the pattern matches are done with =~# to avoid the value of the
+" 'ignorecase' option making a difference. Where case is to be ignored use
+" =~? instead. Do not use =~ anywhere.
" Only do the rest when the FileType autocommand has not been triggered yet.
@@ -28,12 +32,12 @@ set cpo&vim
let s:line1 = getline(1)
-if s:line1 =~ "^#!"
+if s:line1 =~# "^#!"
" A script that starts with "#!".
" Check for a line like "#!/usr/bin/env VAR=val bash". Turn it into
" "#!/usr/bin/bash" to make matching easier.
- if s:line1 =~ '^#!\s*\S*\<env\s'
+ if s:line1 =~# '^#!\s*\S*\<env\s'
let s:line1 = substitute(s:line1, '\S\+=\S\+', '', 'g')
let s:line1 = substitute(s:line1, '\<env\s\+', '', '')
endif
@@ -44,11 +48,11 @@ if s:line1 =~ "^#!"
" "#!/usr/bin/env perl [path/args]"
" If there is no path use the first word: "#!perl [path/args]".
" Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]".
- if s:line1 =~ '^#!\s*\a:[/\\]'
+ if s:line1 =~# '^#!\s*\a:[/\\]'
let s:name = substitute(s:line1, '^#!.*[/\\]\(\i\+\).*', '\1', '')
- elseif s:line1 =~ '^#!.*\<env\>'
+ elseif s:line1 =~# '^#!.*\<env\>'
let s:name = substitute(s:line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '')
- elseif s:line1 =~ '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
+ elseif s:line1 =~# '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
let s:name = substitute(s:line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '')
else
let s:name = substitute(s:line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '')
@@ -56,116 +60,116 @@ if s:line1 =~ "^#!"
" tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
" third line. Suggested by Steven Atkinson.
- if getline(3) =~ '^exec wish'
+ if getline(3) =~# '^exec wish'
let s:name = 'wish'
endif
" Bourne-like shell scripts: bash bash2 ksh ksh93 sh
- if s:name =~ '^\(bash\d*\|\|ksh\d*\|sh\)\>'
- call SetFileTypeSH(s:line1) " defined in filetype.vim
+ if s:name =~# '^\(bash\d*\|\|ksh\d*\|sh\)\>'
+ call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" csh scripts
- elseif s:name =~ '^csh\>'
+ elseif s:name =~# '^csh\>'
if exists("g:filetype_csh")
- call SetFileTypeShell(g:filetype_csh)
+ call dist#ft#SetFileTypeShell(g:filetype_csh)
else
- call SetFileTypeShell("csh")
+ call dist#ft#SetFileTypeShell("csh")
endif
" tcsh scripts
- elseif s:name =~ '^tcsh\>'
- call SetFileTypeShell("tcsh")
+ elseif s:name =~# '^tcsh\>'
+ call dist#ft#SetFileTypeShell("tcsh")
" Z shell scripts
- elseif s:name =~ '^zsh\>'
+ elseif s:name =~# '^zsh\>'
set ft=zsh
" TCL scripts
- elseif s:name =~ '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
+ elseif s:name =~# '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
set ft=tcl
" Expect scripts
- elseif s:name =~ '^expect\>'
+ elseif s:name =~# '^expect\>'
set ft=expect
" Gnuplot scripts
- elseif s:name =~ '^gnuplot\>'
+ elseif s:name =~# '^gnuplot\>'
set ft=gnuplot
" Makefiles
- elseif s:name =~ 'make\>'
+ elseif s:name =~# 'make\>'
set ft=make
" Lua
- elseif s:name =~ 'lua'
+ elseif s:name =~# 'lua'
set ft=lua
" Perl 6
- elseif s:name =~ 'perl6'
+ elseif s:name =~# 'perl6'
set ft=perl6
" Perl
- elseif s:name =~ 'perl'
+ elseif s:name =~# 'perl'
set ft=perl
" PHP
- elseif s:name =~ 'php'
+ elseif s:name =~# 'php'
set ft=php
" Python
- elseif s:name =~ 'python'
+ elseif s:name =~# 'python'
set ft=python
" Groovy
- elseif s:name =~ '^groovy\>'
+ elseif s:name =~# '^groovy\>'
set ft=groovy
" Ruby
- elseif s:name =~ 'ruby'
+ elseif s:name =~# 'ruby'
set ft=ruby
" JavaScript
- elseif s:name =~ 'node\(js\)\=\>' || s:name =~ 'rhino\>'
+ elseif s:name =~# 'node\(js\)\=\>' || s:name =~# 'rhino\>'
set ft=javascript
" BC calculator
- elseif s:name =~ '^bc\>'
+ elseif s:name =~# '^bc\>'
set ft=bc
" sed
- elseif s:name =~ 'sed\>'
+ elseif s:name =~# 'sed\>'
set ft=sed
" OCaml-scripts
- elseif s:name =~ 'ocaml'
+ elseif s:name =~# 'ocaml'
set ft=ocaml
" Awk scripts
- elseif s:name =~ 'awk\>'
+ elseif s:name =~# 'awk\>'
set ft=awk
" Website MetaLanguage
- elseif s:name =~ 'wml'
+ elseif s:name =~# 'wml'
set ft=wml
" Scheme scripts
- elseif s:name =~ 'scheme'
+ elseif s:name =~# 'scheme'
set ft=scheme
" CFEngine scripts
- elseif s:name =~ 'cfengine'
+ elseif s:name =~# 'cfengine'
set ft=cfengine
" Erlang scripts
- elseif s:name =~ 'escript'
+ elseif s:name =~# 'escript'
set ft=erlang
" Haskell
- elseif s:name =~ 'haskell'
+ elseif s:name =~# 'haskell'
set ft=haskell
" Scala
- elseif s:name =~ 'scala\>'
+ elseif s:name =~# 'scala\>'
set ft=scala
endif
@@ -180,28 +184,28 @@ else
let s:line5 = getline(5)
" Bourne-like shell scripts: sh ksh bash bash2
- if s:line1 =~ '^:$'
- call SetFileTypeSH(s:line1) " defined in filetype.vim
+ if s:line1 =~# '^:$'
+ call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" Z shell scripts
- elseif s:line1 =~ '^#compdef\>' || s:line1 =~ '^#autoload\>' ||
- \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~ '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
+ elseif s:line1 =~# '^#compdef\>' || s:line1 =~# '^#autoload\>' ||
+ \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
set ft=zsh
" ELM Mail files
- elseif s:line1 =~ '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
+ elseif s:line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
set ft=mail
" Mason
- elseif s:line1 =~ '^<[%&].*>'
+ elseif s:line1 =~# '^<[%&].*>'
set ft=mason
" Vim scripts (must have '" vim' as the first line to trigger this)
- elseif s:line1 =~ '^" *[vV]im$'
+ elseif s:line1 =~# '^" *[vV]im$'
set ft=vim
" MOO
- elseif s:line1 =~ '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
+ elseif s:line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
set ft=moo
" Diff file:
@@ -215,40 +219,45 @@ else
" - "=== ", "--- ", "+++ " (bzr diff, common case)
" - "=== (removed|added|renamed|modified)" (bzr diff, alternative)
" - "# HG changeset patch" in first line (Mercurial export format)
- elseif s:line1 =~ '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)'
- \ || (s:line1 =~ '^--- ' && s:line2 =~ '^+++ ')
- \ || (s:line1 =~ '^\* looking for ' && s:line2 =~ '^\* comparing to ')
- \ || (s:line1 =~ '^\*\*\* ' && s:line2 =~ '^--- ')
- \ || (s:line1 =~ '^=== ' && ((s:line2 =~ '^=\{66\}' && s:line3 =~ '^--- ' && s:line4 =~ '^+++') || (s:line2 =~ '^--- ' && s:line3 =~ '^+++ ')))
- \ || (s:line1 =~ '^=== \(removed\|added\|renamed\|modified\)')
+ elseif s:line1 =~# '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)'
+ \ || (s:line1 =~# '^--- ' && s:line2 =~# '^+++ ')
+ \ || (s:line1 =~# '^\* looking for ' && s:line2 =~# '^\* comparing to ')
+ \ || (s:line1 =~# '^\*\*\* ' && s:line2 =~# '^--- ')
+ \ || (s:line1 =~# '^=== ' && ((s:line2 =~# '^=\{66\}' && s:line3 =~# '^--- ' && s:line4 =~# '^+++') || (s:line2 =~# '^--- ' && s:line3 =~# '^+++ ')))
+ \ || (s:line1 =~# '^=== \(removed\|added\|renamed\|modified\)')
set ft=diff
" PostScript Files (must have %!PS as the first line, like a2ps output)
- elseif s:line1 =~ '^%![ \t]*PS'
+ elseif s:line1 =~# '^%![ \t]*PS'
set ft=postscr
" M4 scripts: Guess there is a line that starts with "dnl".
- elseif s:line1 =~ '^\s*dnl\>'
- \ || s:line2 =~ '^\s*dnl\>'
- \ || s:line3 =~ '^\s*dnl\>'
- \ || s:line4 =~ '^\s*dnl\>'
- \ || s:line5 =~ '^\s*dnl\>'
+ elseif s:line1 =~# '^\s*dnl\>'
+ \ || s:line2 =~# '^\s*dnl\>'
+ \ || s:line3 =~# '^\s*dnl\>'
+ \ || s:line4 =~# '^\s*dnl\>'
+ \ || s:line5 =~# '^\s*dnl\>'
set ft=m4
+ " AmigaDos scripts
+ elseif $TERM == "amiga"
+ \ && (s:line1 =~# "^;" || s:line1 =~? '^\.bra')
+ set ft=amiga
+
" SiCAD scripts (must have procn or procd as the first line to trigger this)
elseif s:line1 =~? '^ *proc[nd] *$'
set ft=sicad
" Purify log files start with "**** Purify"
- elseif s:line1 =~ '^\*\*\*\* Purify'
+ elseif s:line1 =~# '^\*\*\*\* Purify'
set ft=purifylog
" XML
- elseif s:line1 =~ '<?\s*xml.*?>'
+ elseif s:line1 =~# '<?\s*xml.*?>'
set ft=xml
" XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN")
- elseif s:line1 =~ '\<DTD\s\+XHTML\s'
+ elseif s:line1 =~# '\<DTD\s\+XHTML\s'
set ft=xhtml
" HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN")
@@ -257,43 +266,43 @@ else
set ft=html
" PDF
- elseif s:line1 =~ '^%PDF-'
+ elseif s:line1 =~# '^%PDF-'
set ft=pdf
" XXD output
- elseif s:line1 =~ '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
+ elseif s:line1 =~# '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
set ft=xxd
" RCS/CVS log output
- elseif s:line1 =~ '^RCS file:' || s:line2 =~ '^RCS file:'
+ elseif s:line1 =~# '^RCS file:' || s:line2 =~# '^RCS file:'
set ft=rcslog
" CVS commit
- elseif s:line2 =~ '^CVS:' || getline("$") =~ '^CVS: '
+ elseif s:line2 =~# '^CVS:' || getline("$") =~# '^CVS: '
set ft=cvs
" Prescribe
- elseif s:line1 =~ '^!R!'
+ elseif s:line1 =~# '^!R!'
set ft=prescribe
" Send-pr
- elseif s:line1 =~ '^SEND-PR:'
+ elseif s:line1 =~# '^SEND-PR:'
set ft=sendpr
" SNNS files
- elseif s:line1 =~ '^SNNS network definition file'
+ elseif s:line1 =~# '^SNNS network definition file'
set ft=snnsnet
- elseif s:line1 =~ '^SNNS pattern definition file'
+ elseif s:line1 =~# '^SNNS pattern definition file'
set ft=snnspat
- elseif s:line1 =~ '^SNNS result file'
+ elseif s:line1 =~# '^SNNS result file'
set ft=snnsres
" Virata
- elseif s:line1 =~ '^%.\{-}[Vv]irata'
- \ || s:line2 =~ '^%.\{-}[Vv]irata'
- \ || s:line3 =~ '^%.\{-}[Vv]irata'
- \ || s:line4 =~ '^%.\{-}[Vv]irata'
- \ || s:line5 =~ '^%.\{-}[Vv]irata'
+ elseif s:line1 =~# '^%.\{-}[Vv]irata'
+ \ || s:line2 =~# '^%.\{-}[Vv]irata'
+ \ || s:line3 =~# '^%.\{-}[Vv]irata'
+ \ || s:line4 =~# '^%.\{-}[Vv]irata'
+ \ || s:line5 =~# '^%.\{-}[Vv]irata'
set ft=virata
" Strace
@@ -301,17 +310,17 @@ else
set ft=strace
" VSE JCL
- elseif s:line1 =~ '^\* $$ JOB\>' || s:line1 =~ '^// *JOB\>'
+ elseif s:line1 =~# '^\* $$ JOB\>' || s:line1 =~# '^// *JOB\>'
set ft=vsejcl
" TAK and SINDA
- elseif s:line4 =~ 'K & K Associates' || s:line2 =~ 'TAK 2000'
+ elseif s:line4 =~# 'K & K Associates' || s:line2 =~# 'TAK 2000'
set ft=takout
- elseif s:line3 =~ 'S Y S T E M S I M P R O V E D '
+ elseif s:line3 =~# 'S Y S T E M S I M P R O V E D '
set ft=sindaout
- elseif getline(6) =~ 'Run Date: '
+ elseif getline(6) =~# 'Run Date: '
set ft=takcmp
- elseif getline(9) =~ 'Node File 1'
+ elseif getline(9) =~# 'Node File 1'
set ft=sindacmp
" DNS zone files
@@ -319,34 +328,34 @@ else
set ft=bindzone
" BAAN
- elseif s:line1 =~ '|\*\{1,80}' && s:line2 =~ 'VRC '
- \ || s:line2 =~ '|\*\{1,80}' && s:line3 =~ 'VRC '
+ elseif s:line1 =~# '|\*\{1,80}' && s:line2 =~# 'VRC '
+ \ || s:line2 =~# '|\*\{1,80}' && s:line3 =~# 'VRC '
set ft=baan
" Valgrind
- elseif s:line1 =~ '^==\d\+== valgrind' || s:line3 =~ '^==\d\+== Using valgrind'
+ elseif s:line1 =~# '^==\d\+== valgrind' || s:line3 =~# '^==\d\+== Using valgrind'
set ft=valgrind
" Go docs
- elseif s:line1 =~ '^PACKAGE DOCUMENTATION$'
+ elseif s:line1 =~# '^PACKAGE DOCUMENTATION$'
set ft=godoc
" Renderman Interface Bytestream
- elseif s:line1 =~ '^##RenderMan'
+ elseif s:line1 =~# '^##RenderMan'
set ft=rib
" Scheme scripts
- elseif s:line1 =~ 'exec\s\+\S*scheme' || s:line2 =~ 'exec\s\+\S*scheme'
+ elseif s:line1 =~# 'exec\s\+\S*scheme' || s:line2 =~# 'exec\s\+\S*scheme'
set ft=scheme
" Git output
- elseif s:line1 =~ '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$'
+ elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$'
set ft=git
" Gprof (gnu profiler)
elseif s:line1 == 'Flat profile:'
\ && s:line2 == ''
- \ && s:line3 =~ '^Each sample counts as .* seconds.$'
+ \ && s:line3 =~# '^Each sample counts as .* seconds.$'
set ft=gprof
" Erlang terms
@@ -357,18 +366,18 @@ else
" CVS diff
else
let s:lnum = 1
- while getline(s:lnum) =~ "^? " && s:lnum < line("$")
+ while getline(s:lnum) =~# "^? " && s:lnum < line("$")
let s:lnum += 1
endwhile
- if getline(s:lnum) =~ '^Index:\s\+\f\+$'
+ if getline(s:lnum) =~# '^Index:\s\+\f\+$'
set ft=diff
" locale input files: Formal Definitions of Cultural Conventions
" filename must be like en_US, fr_FR@euro or en_US.UTF-8
- elseif expand("%") =~ '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
+ elseif expand("%") =~# '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
let s:lnum = 1
while s:lnum < 100 && s:lnum < line("$")
- if getline(s:lnum) =~ '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
+ if getline(s:lnum) =~# '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
setf fdcc
break
endif
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 606baff619..2728ae9b06 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -359,6 +359,10 @@ endforeach()
# Our dependencies come first.
+if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ list(APPEND NVIM_LINK_LIBRARIES pthread c++abi)
+endif()
+
if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif()
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 117d89d24c..a0f6ce152b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -3623,6 +3623,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
memset(cptext, 0, sizeof(cptext));
}
if (word == NULL || (!aempty && *word == NUL)) {
+ for (size_t i = 0; i < CPT_COUNT; i++) {
+ xfree(cptext[i]);
+ }
return FAIL;
}
return ins_compl_add((char_u *)word, -1, icase, NULL,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 52686f6651..02f72dbce3 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1,9 +1,7 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * fileio.c: read from and write to a file
- */
+// fileio.c: read from and write to a file
#include <assert.h>
#include <errno.h>
@@ -65,57 +63,62 @@
#define BUFSIZE 8192 /* size of normal write buffer */
#define SMBUFSIZE 256 /* size of emergency write buffer */
-/*
- * The autocommands are stored in a list for each event.
- * Autocommands for the same pattern, that are consecutive, are joined
- * together, to avoid having to match the pattern too often.
- * The result is an array of Autopat lists, which point to AutoCmd lists:
- *
- * first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
- * Autopat.cmds Autopat.cmds
- * | |
- * V V
- * AutoCmd.next AutoCmd.next
- * | |
- * V V
- * AutoCmd.next NULL
- * |
- * V
- * NULL
- *
- * first_autopat[1] --> Autopat.next --> NULL
- * Autopat.cmds
- * |
- * V
- * AutoCmd.next
- * |
- * V
- * NULL
- * etc.
- *
- * The order of AutoCmds is important, this is the order in which they were
- * defined and will have to be executed.
- */
+//
+// The autocommands are stored in a list for each event.
+// Autocommands for the same pattern, that are consecutive, are joined
+// together, to avoid having to match the pattern too often.
+// The result is an array of Autopat lists, which point to AutoCmd lists:
+//
+// last_autopat[0] -----------------------------+
+// V
+// first_autopat[0] --> Autopat.next --> Autopat.next --> NULL
+// Autopat.cmds Autopat.cmds
+// | |
+// V V
+// AutoCmd.next AutoCmd.next
+// | |
+// V V
+// AutoCmd.next NULL
+// |
+// V
+// NULL
+//
+// last_autopat[1] --------+
+// V
+// first_autopat[1] --> Autopat.next --> NULL
+// Autopat.cmds
+// |
+// V
+// AutoCmd.next
+// |
+// V
+// NULL
+// etc.
+//
+// The order of AutoCmds is important, this is the order in which they were
+// defined and will have to be executed.
+//
typedef struct AutoCmd {
- char_u *cmd; /* The command to be executed (NULL
- when command has been removed) */
- char nested; /* If autocommands nest here */
- char last; /* last command in list */
- scid_T scriptID; /* script ID where defined */
- struct AutoCmd *next; /* Next AutoCmd in list */
+ char_u *cmd; // The command to be executed (NULL
+ // when command has been removed)
+ char nested; // If autocommands nest here
+ char last; // last command in list
+ scid_T scriptID; // script ID where defined
+ struct AutoCmd *next; // Next AutoCmd in list
} AutoCmd;
typedef struct AutoPat {
- char_u *pat; /* pattern as typed (NULL when pattern
- has been removed) */
- regprog_T *reg_prog; /* compiled regprog for pattern */
- AutoCmd *cmds; /* list of commands to do */
- struct AutoPat *next; /* next AutoPat in AutoPat list */
- int group; /* group ID */
- int patlen; /* strlen() of pat */
- int buflocal_nr; /* !=0 for buffer-local AutoPat */
- char allow_dirs; /* Pattern may match whole path */
- char last; /* last pattern for apply_autocmds() */
+ struct AutoPat *next; // next AutoPat in AutoPat list; MUST
+ // be the first entry
+ char_u *pat; // pattern as typed (NULL when pattern
+ // has been removed)
+ regprog_T *reg_prog; // compiled regprog for pattern
+ AutoCmd *cmds; // list of commands to do
+ int group; // group ID
+ int patlen; // strlen() of pat
+ int buflocal_nr; // !=0 for buffer-local AutoPat
+ char allow_dirs; // Pattern may match whole path
+ char last; // last pattern for apply_autocmds()
} AutoPat;
/*
@@ -226,6 +229,15 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
msg_scrolled_ign = FALSE;
}
+static AutoPat *last_autopat[NUM_EVENTS] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
/*
* Read lines from file "fname" into the buffer after line "from".
*
@@ -5528,6 +5540,15 @@ static void au_cleanup(void)
/* remove the pattern if it has been marked for deletion */
if (ap->pat == NULL) {
+ if (ap->next == NULL) {
+ if (prev_ap == &(first_autopat[(int)event])) {
+ last_autopat[(int)event] = NULL;
+ } else {
+ // this depends on the "next" field being the first in
+ // the struct
+ last_autopat[(int)event] = (AutoPat *)prev_ap;
+ }
+ }
*prev_ap = ap->next;
vim_regfree(ap->reg_prog);
xfree(ap);
@@ -6120,10 +6141,13 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
patlen = (int)STRLEN(buflocal_pat); /* but not endpat */
}
- /*
- * Find AutoPat entries with this pattern.
- */
- prev_ap = &first_autopat[(int)event];
+ // Find AutoPat entries with this pattern. When adding a command it
+ // always goes at or after the last one, so start at the end.
+ if (!forceit && *cmd != NUL && last_autopat[(int)event] != NULL) {
+ prev_ap = &last_autopat[(int)event];
+ } else {
+ prev_ap = &first_autopat[(int)event];
+ }
while ((ap = *prev_ap) != NULL) {
if (ap->pat != NULL) {
/* Accept a pattern when:
@@ -6209,6 +6233,7 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
}
ap->cmds = NULL;
*prev_ap = ap;
+ last_autopat[(int)event] = ap;
ap->next = NULL;
if (group == AUGROUP_ALL)
ap->group = current_augroup;
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 4e01265498..348df2d9b6 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -136,13 +136,21 @@
# define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
-/// Calculate the length of a C array.
+/// Calculate the length of a C array
///
/// This should be called with a real array. Calling this with a pointer is an
-/// error. A mechanism to detect many (though not all) of those errors at compile
-/// time is implemented. It works by the second division producing a division by
-/// zero in those cases (-Wdiv-by-zero in GCC).
-#define ARRAY_SIZE(arr) ((sizeof(arr)/sizeof((arr)[0])) / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+/// error. A mechanism to detect many (though not all) of those errors at
+/// compile time is implemented. It works by the second division producing
+/// a division by zero in those cases (-Wdiv-by-zero in GCC).
+#define ARRAY_SIZE(arr) \
+ ((sizeof(arr)/sizeof((arr)[0])) \
+ / ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
+
+/// Get last array entry
+///
+/// This should be called with a real array. Calling this with a pointer is an
+/// error.
+#define ARRAY_LAST_ENTRY(arr) (arr)[ARRAY_SIZE(arr) - 1]
// Duplicated in os/win_defs.h to avoid include-order sensitivity.
#define RGB_(r, g, b) ((r << 16) | (g << 8) | b)
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
index 63eea9022b..a67e7487eb 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/process.c
@@ -18,7 +18,7 @@
# include <sys/user.h>
#endif
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/param.h>
#endif
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index d01eff6384..94cc63baea 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -139,17 +139,17 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
endmacro()
# Create some translations from others.
- if("ja" IN_LIST LANGUAGES)
+ if(";${LANGUAGES};" MATCHES ";ja;")
BuildPoIconv(ja utf-8 euc-jp)
BuildMo(ja.euc-jp)
endif()
- if("cs" IN_LIST LANGUAGES)
+ if(";${LANGUAGES};" MATCHES ";cs;")
BuildPoIconv(cs ISO-8859-2 cp1250)
BuildMo(cs.cp1250)
endif()
- if("sk" IN_LIST LANGUAGES)
+ if(";${LANGUAGES};" MATCHES ";sk;")
BuildPoIconv(sk ISO-8859-2 cp1250)
BuildMo(sk.cp1250)
endif()
@@ -159,7 +159,7 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
${CMAKE_CURRENT_SOURCE_DIR}/no.po ${CMAKE_CURRENT_SOURCE_DIR}/nb.po
DEPENDS no.po)
list(APPEND UPDATE_PO_TARGETS update-po-nb)
- if("nb" IN_LIST LANGUAGES)
+ if(";${LANGUAGES};" MATCHES ";no;")
CheckPo(nb)
BuildMo(nb)
endif()
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2d8c353f92..46124e0672 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3029,7 +3029,7 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
/*
* Return TRUE if "buf" is the quickfix buffer.
*/
-int bt_quickfix(buf_T *buf)
+int bt_quickfix(const buf_T *const buf)
{
return buf != NULL && buf->b_p_bt[0] == 'q';
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 05ad126fa0..731bb2658a 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2044,7 +2044,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width,
- wp->w_width, false, wp);
+ wp->w_width, false, wp, 0);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -2465,10 +2465,6 @@ win_line (
line_attr = win_hl_attr(wp, HLF_QFL);
}
- if (wp->w_hl_attr_normal != 0) {
- line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
- }
-
if (line_attr != 0) {
area_highlighting = true;
}
@@ -2926,7 +2922,8 @@ win_line (
&& lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol
&& filler_todo <= 0
) {
- screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp);
+ screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -4019,7 +4016,8 @@ win_line (
col++;
}
}
- screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp);
+ screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp,
+ wp->w_hl_attr_normal);
row++;
/*
@@ -4242,7 +4240,7 @@ win_line (
|| (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
) {
screen_line(screen_row, wp->w_wincol, col - boguscols,
- wp->w_width, wp->w_p_rl, wp);
+ wp->w_width, wp->w_p_rl, wp, wp->w_hl_attr_normal);
boguscols = 0;
++row;
++screen_row;
@@ -4412,7 +4410,7 @@ static int char_needs_redraw(int off_from, int off_to, int cols)
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
*/
static void screen_line(int row, int coloff, int endcol,
- int clear_width, int rlflag, win_T *wp)
+ int clear_width, int rlflag, win_T *wp, int bg_attr)
{
unsigned off_from;
unsigned off_to;
@@ -4445,15 +4443,16 @@ static void screen_line(int row, int coloff, int endcol,
/* Clear rest first, because it's left of the text. */
if (clear_width > 0) {
while (col <= endcol && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
- if (col <= endcol)
- screen_fill(row, row + 1, col + coloff,
- endcol + coloff + 1, ' ', ' ', 0);
+ if (col <= endcol) {
+ screen_fill(row, row + 1, col + coloff, endcol + coloff + 1, ' ', ' ',
+ bg_attr);
+ }
}
col = endcol + 1;
off_to = LineOffset[row] + col + coloff;
@@ -4461,6 +4460,13 @@ static void screen_line(int row, int coloff, int endcol,
endcol = (clear_width > 0 ? clear_width : -clear_width);
}
+ if (bg_attr) {
+ for (int c = col; c < endcol; c++) {
+ ScreenAttrs[off_from+c] = hl_combine_attr(bg_attr,
+ ScreenAttrs[off_from+c]);
+ }
+ }
+
redraw_next = char_needs_redraw(off_from, off_to, endcol - col);
while (col < endcol) {
@@ -4559,15 +4565,15 @@ static void screen_line(int row, int coloff, int endcol,
/* blank out the rest of the line */
while (col < clear_width && ScreenLines[off_to] == ' '
- && ScreenAttrs[off_to] == 0
+ && ScreenAttrs[off_to] == bg_attr
&& (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
}
if (col < clear_width) {
- screen_fill(row, row + 1, col + coloff, clear_width + coloff,
- ' ', ' ', 0);
+ screen_fill(row, row + 1, col + coloff, clear_width + coloff, ' ', ' ',
+ bg_attr);
off_to += clear_width - col;
col = clear_width;
}
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 605d9c30a6..15ac28e1bf 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -16,12 +16,14 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/vim.h"
+#include "nvim/pos.h"
#include "nvim/ascii.h"
#include "nvim/shada.h"
#include "nvim/message.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/mark.h"
+#include "nvim/macros.h"
#include "nvim/ops.h"
#include "nvim/garray.h"
#include "nvim/option.h"
@@ -375,7 +377,8 @@ KHASH_MAP_INIT_STR(file_marks, FileMarks)
/// Before actually writing most of the data is read to this structure.
typedef struct {
HistoryMergerState hms[HIST_COUNT]; ///< Structures for history merging.
- PossiblyFreedShadaEntry global_marks[NGLOBALMARKS]; ///< All global marks.
+ PossiblyFreedShadaEntry global_marks[NMARKS]; ///< Named global marks.
+ PossiblyFreedShadaEntry numbered_marks[EXTRA_MARKS]; ///< Numbered marks.
PossiblyFreedShadaEntry registers[NUM_SAVED_REGISTERS]; ///< All registers.
PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; ///< All dumped jumps.
size_t jumps_size; ///< Number of jumps occupied.
@@ -2020,6 +2023,113 @@ shada_parse_msgpack_extra_bytes:
return ret;
}
+/// Format shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_entry(const ShadaEntry entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ static char ret[1024];
+ ret[0] = 0;
+ vim_snprintf(S_LEN(ret), "[ ] ts=%" PRIu64 " ");
+ // ^ Space for `can_free_entry`
+ switch (entry.type) {
+ case kSDItemMissing: {
+ vim_snprintf_add(S_LEN(ret), "Missing");
+ break;
+ }
+ case kSDItemHeader: {
+ vim_snprintf_add(S_LEN(ret), "Header { TODO }");
+ break;
+ }
+ case kSDItemBufferList: {
+ vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
+ break;
+ }
+ case kSDItemUnknown: {
+ vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
+ break;
+ }
+ case kSDItemSearchPattern: {
+ vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
+ break;
+ }
+ case kSDItemSubString: {
+ vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
+ break;
+ }
+ case kSDItemHistoryEntry: {
+ vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
+ break;
+ }
+ case kSDItemRegister: {
+ vim_snprintf_add(S_LEN(ret), "Register { TODO }");
+ break;
+ }
+ case kSDItemVariable: {
+ vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
+ break;
+ }
+#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
+ do { \
+ typval_T ad_tv = { \
+ .v_type = VAR_DICT, \
+ .vval.v_dict = entry.data.filemark.additional_data \
+ }; \
+ size_t ad_len; \
+ char *const ad = encode_tv2string(&ad_tv, &ad_len); \
+ vim_snprintf_add( \
+ S_LEN(ret), \
+ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
+ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
+ "ad={%p:[%zu]%.64s} }", \
+ name_fmt_arg, \
+ strlen(entry.data.filemark.fname), \
+ entry.data.filemark.fname, \
+ entry.data.filemark.mark.lnum, \
+ entry.data.filemark.mark.col, \
+ entry.data.filemark.mark.coladd, \
+ entry.data.filemark.additional_data, \
+ ad_len, \
+ ad); \
+ } while (0)
+ case kSDItemGlobalMark: {
+ FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemChange: {
+ FORMAT_MARK_ENTRY("Change", "%s", "");
+ break;
+ }
+ case kSDItemLocalMark: {
+ FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ }
+ case kSDItemJump: {
+ FORMAT_MARK_ENTRY("Jump", "%s", "");
+ break;
+ }
+#undef FORMAT_MARK_ENTRY
+ }
+ return ret;
+}
+
+/// Format possibly freed shada entry for debugging purposes
+///
+/// @param[in] entry ShaDa entry to format.
+///
+/// @return string representing ShaDa entry in a static buffer.
+static const char *shada_format_pfreed_entry(
+ const PossiblyFreedShadaEntry pfs_entry)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
+{
+ char *ret = (char *)shada_format_entry(pfs_entry.data);
+ ret[1] = (pfs_entry.can_free_entry ? 'T' : 'F');
+ return ret;
+}
+
/// Read and merge in ShaDa file, used when writing
///
/// @param[in] sd_reader Structure containing file reader definition.
@@ -2071,9 +2181,12 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data); \
} \
} \
- wms_entry->can_free_entry = true; \
- wms_entry->data = (entry); \
+ *wms_entry = pfs_entry; \
} while (0)
+ const PossiblyFreedShadaEntry pfs_entry = {
+ .can_free_entry = true,
+ .data = entry,
+ };
switch (entry.type) {
case kSDItemMissing: {
break;
@@ -2125,13 +2238,49 @@ static inline ShaDaWriteResult shada_read_when_writing(
break;
}
case kSDItemGlobalMark: {
- const int idx = mark_global_index(entry.data.filemark.name);
- if (idx < 0) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
+ if (ascii_isdigit(entry.data.filemark.name)) {
+ bool processed_mark = false;
+ // Completely ignore numbered mark names, make a list sorted by
+ // timestamp.
+ for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
+ ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
+ if (wms_entry.type != kSDItemGlobalMark) {
+ continue;
+ }
+ // Ignore duplicates.
+ if (wms_entry.timestamp == entry.timestamp
+ && (wms_entry.data.filemark.additional_data == NULL
+ && entry.data.filemark.additional_data == NULL)
+ && marks_equal(wms_entry.data.filemark.mark,
+ entry.data.filemark.mark)
+ && strcmp(wms_entry.data.filemark.fname,
+ entry.data.filemark.fname) == 0) {
+ shada_free_shada_entry(&entry);
+ processed_mark = true;
+ break;
+ }
+ if (wms_entry.timestamp >= entry.timestamp) {
+ processed_mark = true;
+ if (i < ARRAY_SIZE(wms->numbered_marks)) {
+ replace_numbered_mark(wms, i, pfs_entry);
+ } else {
+ shada_free_shada_entry(&entry);
+ }
+ break;
+ }
+ }
+ if (!processed_mark) {
+ replace_numbered_mark(wms, 0, pfs_entry);
+ }
+ } else {
+ const int idx = mark_global_index(entry.data.filemark.name);
+ if (idx < 0) {
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
+ break;
+ }
+ COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
}
- COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
break;
}
case kSDItemChange:
@@ -2175,8 +2324,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
shada_free_shada_entry(&wms_entry->data);
}
}
- wms_entry->can_free_entry = true;
- wms_entry->data = entry;
+ *wms_entry = pfs_entry;
}
} else {
#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
@@ -2216,6 +2364,20 @@ static inline ShaDaWriteResult shada_read_when_writing(
return ret;
}
+/// Check whether buffer should be ignored
+///
+/// @param[in] buf buf_T* to check.
+/// @param[in] removable_bufs Cache of buffers ignored due to their location.
+///
+/// @return true or false.
+static inline bool ignore_buf(const buf_T *const buf,
+ khash_t(bufset) *const removable_bufs)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+{
+ return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
+ || in_bufset(removable_bufs, buf));
+}
+
/// Get list of buffers to write to the shada file
///
/// @param[in] removable_bufs Buffers which are ignored
@@ -2227,11 +2389,9 @@ static inline ShadaEntry shada_get_buflist(
{
int max_bufs = get_shada_parameter('%');
size_t buf_count = 0;
-#define IGNORE_BUF(buf)\
- (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
- || in_bufset(removable_bufs, buf)) // NOLINT(whitespace/indent)
FOR_ALL_BUFFERS(buf) {
- if (!IGNORE_BUF(buf) && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
+ if (!ignore_buf(buf, removable_bufs)
+ && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
buf_count++;
}
}
@@ -2249,7 +2409,7 @@ static inline ShadaEntry shada_get_buflist(
};
size_t i = 0;
FOR_ALL_BUFFERS(buf) {
- if (IGNORE_BUF(buf)) {
+ if (ignore_buf(buf, removable_bufs)) {
continue;
}
if (i >= buf_count) {
@@ -2263,7 +2423,6 @@ static inline ShadaEntry shada_get_buflist(
i++;
}
-#undef IGNORE_BUF
return buflist_entry;
}
@@ -2365,6 +2524,34 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
} while (reg_iter != NULL);
}
+/// Replace numbered mark in WriteMergerState
+///
+/// Frees the last mark, moves (including adjusting mark names) marks from idx
+/// to the last-but-one one and saves the new mark at given index.
+///
+/// @param[out] wms Merger state to adjust.
+/// @param[in] idx Index at which new mark should be placed.
+/// @param[in] entry New mark.
+static inline void replace_numbered_mark(WriteMergerState *const wms,
+ const size_t idx,
+ const PossiblyFreedShadaEntry entry)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
+{
+ if (ARRAY_LAST_ENTRY(wms->numbered_marks).can_free_entry) {
+ shada_free_shada_entry(&ARRAY_LAST_ENTRY(wms->numbered_marks).data);
+ }
+ for (size_t i = idx; i < ARRAY_SIZE(wms->numbered_marks) - 1; i++) {
+ if (wms->numbered_marks[i].data.type == kSDItemGlobalMark) {
+ wms->numbered_marks[i].data.data.filemark.name = (char)('0' + (int)i + 1);
+ }
+ }
+ memmove(wms->numbered_marks + idx + 1, wms->numbered_marks + idx,
+ sizeof(wms->numbered_marks[0])
+ * (ARRAY_SIZE(wms->numbered_marks) - 1 - idx));
+ wms->numbered_marks[idx] = entry;
+ wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx);
+}
+
/// Write ShaDa file
///
/// @param[in] sd_writer Structure containing file writer definition.
@@ -2597,6 +2784,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
// Initialize global marks
if (dump_global_marks) {
const void *global_mark_iter = NULL;
+ size_t digit_mark_idx = 0;
do {
char name = NUL;
xfmark_T fm;
@@ -2619,7 +2807,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
fname = (const char *) buf->b_ffname;
}
- wms->global_marks[mark_global_index(name)] = (PossiblyFreedShadaEntry) {
+ const PossiblyFreedShadaEntry pf_entry = {
.can_free_entry = false,
.data = {
.type = kSDItemGlobalMark,
@@ -2629,11 +2817,16 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.mark = fm.fmark.mark,
.name = name,
.additional_data = fm.fmark.additional_data,
- .fname = (char *) fname,
+ .fname = (char *)fname,
}
}
},
};
+ if (ascii_isdigit(name)) {
+ replace_numbered_mark(wms, digit_mark_idx++, pf_entry);
+ } else {
+ wms->global_marks[mark_global_index(name)] = pf_entry;
+ }
} while (global_mark_iter != NULL);
}
@@ -2715,6 +2908,26 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
}
+ // Update numbered marks: '0' should be replaced with the current position,
+ // '9' should be removed and all other marks shifted.
+ if (!ignore_buf(curbuf, &removable_bufs) && curwin->w_cursor.lnum != 0) {
+ replace_numbered_mark(wms, 0, (PossiblyFreedShadaEntry) {
+ .can_free_entry = false,
+ .data = {
+ .type = kSDItemGlobalMark,
+ .timestamp = os_time(),
+ .data = {
+ .filemark = {
+ .mark = curwin->w_cursor,
+ .name = '0',
+ .additional_data = NULL,
+ .fname = (char *)curbuf->b_ffname,
+ }
+ }
+ },
+ });
+ }
+
// Write the rest
#define PACK_WMS_ARRAY(wms_array) \
do { \
@@ -2729,6 +2942,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
} \
} while (0)
PACK_WMS_ARRAY(wms->global_marks);
+ PACK_WMS_ARRAY(wms->numbered_marks);
PACK_WMS_ARRAY(wms->registers);
for (size_t i = 0; i < wms->jumps_size; i++) {
if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte)
@@ -2823,6 +3037,7 @@ shada_write_exit:
return ret;
}
+#undef IGNORE_BUF
#undef PACK_STATIC_STR
/// Write ShaDa file to a given location
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 7a15c8908b..a628baff53 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -525,6 +525,85 @@ describe('ShaDa marks support code', function()
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
end)
+ it('can merge with file with mark 9 as the only numeric mark', function()
+ wshada('\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ nvim_command('normal! `9oabc')
+ eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
+ end
+ end
+ eq({['0']=1, ['1']=1}, found)
+ end)
+
+ it('removes duplicates while merging', function()
+ wshada('\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9'
+ .. '\007\001\014\130\161f\196\006' .. mock_file_path .. '-\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = 0
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ print(require('test.helpers').format_luav(v))
+ found = found + 1
+ end
+ end
+ eq(1, found)
+ end)
+
+ it('does not leak when no append is performed due to too many marks',
+ function()
+ wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'a\161n0'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'b\161n1'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161n2'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161n3'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161n4'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161n5'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'g\161n6'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'h\161n7'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'i\161n8'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'j\161n9'
+ .. '\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'k\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f:sub(1, #mock_file_path) == mock_file_path then
+ found[#found + 1] = v.value.f:sub(#v.value.f)
+ end
+ end
+ eq({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}, found)
+ end)
+
+ it('does not leak when last mark in file removes some of the earlier ones',
+ function()
+ wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'a\161n0'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'b\161n1'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161n2'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'd\161n3'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'e\161n4'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161n5'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'g\161n6'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'h\161n7'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'i\161n8'
+ .. '\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'j\161n9'
+ .. '\007\003\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'k\161n9')
+ eq(0, exc_exec(sdrcmd()))
+ eq(0, exc_exec('wshada ' .. shada_fname))
+ local found = {}
+ for _, v in ipairs(read_shada_file(shada_fname)) do
+ if v.type == 7 and v.value.f:sub(1, #mock_file_path) == mock_file_path then
+ found[#found + 1] = v.value.f:sub(#v.value.f)
+ end
+ end
+ eq({'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'}, found)
+ end)
+
it('uses last A mark with gt timestamp from file when reading with !',
function()
wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
@@ -563,13 +642,14 @@ describe('ShaDa marks support code', function()
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '' .. mock_file_path .. '-' then
- found = found + 1
+ if v.type == 7 and v.value.f == mock_file_path .. '-' then
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
end
end
- eq(1, found)
+ eq({['0']=1, A=1}, found)
end)
it('uses last A mark with eq timestamp from instance when writing',
@@ -580,30 +660,33 @@ describe('ShaDa marks support code', function()
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
if v.type == 7 and v.value.f == mock_file_path .. '-' then
- found = found + 1
+ local name = ('%c'):format(v.value.n)
+ found[name] = (found[name] or 0) + 1
end
end
- eq(1, found)
+ eq({['0']=1, A=1}, found)
end)
- it('uses last A mark with gt timestamp from file when writing',
- function()
+ it('uses last A mark with gt timestamp from file when writing', function()
wshada('\007\001\018\131\162mX\195\161f\196\006' .. mock_file_path .. '-\161nA')
eq(0, exc_exec(sdrcmd()))
wshada('\007\002\018\131\162mX\195\161f\196\006' .. mock_file_path .. '?\161nA')
nvim_command('normal! `A')
eq('-', funcs.fnamemodify(curbufmeths.get_name(), ':t'))
eq(0, exc_exec('wshada ' .. shada_fname))
- local found = 0
+ local found = {}
for _, v in ipairs(read_shada_file(shada_fname)) do
- if v.type == 7 and v.value.f == '' .. mock_file_path .. '?' then
- found = found + 1
+ if v.type == 7 then
+ local name = ('%c'):format(v.value.n)
+ local t = found[name] or {}
+ t[v.value.f] = (t[v.value.f] or 0) + 1
+ found[name] = t
end
end
- eq(1, found)
+ eq({['0']={[mock_file_path .. '-']=1}, A={[mock_file_path .. '?']=1}}, found)
end)
it('uses last a mark with gt timestamp from instance when reading',
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index ca44026852..720855860a 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -181,13 +181,13 @@ describe('ShaDa support code', function()
nvim_command('set shada+=%')
nvim_command('wshada! ' .. shada_fname)
local readme_fname = funcs.resolve(paths.test_source_path) .. '/README.md'
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
nvim_command('set shada+=r~')
nvim_command('wshada! ' .. shada_fname)
eq({}, find_file(readme_fname))
nvim_command('set shada-=r~')
nvim_command('wshada! ' .. shada_fname)
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname))
nvim_command('set shada+=r' .. funcs.escape(
funcs.escape(paths.test_source_path, '$~'), ' "\\,'))
nvim_command('wshada! ' .. shada_fname)
@@ -206,7 +206,7 @@ describe('ShaDa support code', function()
nvim_command('undo')
nvim_command('set shada+=%')
nvim_command('wshada! ' .. shada_fname)
- eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=2}, find_file(fname))
+ eq({[7]=2, [8]=2, [9]=1, [10]=4, [11]=2}, find_file(fname))
nvim_command('set shada+=r' .. pwd .. '/АБВ')
nvim_command('wshada! ' .. shada_fname)
eq({}, find_file(fname))
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 364e0eea7f..ab3b1c3cac 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -778,6 +778,9 @@ describe("'winhighlight' highlight", function()
[22] = {bold = true, foreground = Screen.colors.SeaGreen4},
[23] = {background = Screen.colors.LightMagenta},
[24] = {background = Screen.colors.WebGray},
+ [25] = {bold = true, foreground = Screen.colors.Green1},
+ [26] = {background = Screen.colors.Red},
+ [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1},
})
command("hi Background1 guibg=DarkBlue")
command("hi Background2 guibg=DarkGreen")
@@ -1047,6 +1050,39 @@ describe("'winhighlight' highlight", function()
]])
end)
+ it("background doesn't override syntax background", function()
+ command('syntax on')
+ command('syntax keyword Foobar foobar')
+ command('syntax keyword Article the')
+ command('hi Foobar guibg=#FF0000')
+ command('hi Article guifg=#00FF00 gui=bold')
+ insert('the foobar was foobar')
+ screen:expect([[
+ {25:the} {26:foobar} was {26:fooba}|
+ {26:^r} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ -- winhl=Normal:Group with background doesn't override syntax background,
+ -- but does combine with syntax foreground.
+ command('set winhl=Normal:Background1')
+ screen:expect([[
+ {27:the}{1: }{26:foobar}{1: was }{26:fooba}|
+ {26:^r}{1: }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
it('can override NonText, Conceal and EndOfBuffer', function()
curbufmeths.set_lines(0,-1,true, {"raa\000"})
command('call matchaddpos("Conceal", [[1,2]], 0, -1, {"conceal": "#"})')
diff --git a/test/helpers.lua b/test/helpers.lua
index 91ceed4df1..7cce6d8c55 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -469,6 +469,8 @@ format_luav = function(v, indent, opts)
end
elseif type(v) == 'nil' then
ret = 'nil'
+ elseif type(v) == 'boolean' then
+ ret = (v and 'true' or 'false')
else
print(type(v))
-- Not implemented yet
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index d082e8d883..30503e3c4a 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -124,13 +124,8 @@ set(LUAROCKS_SHA256 ea1881d6954f2a98c34f93674571c8f0cbdbc28dedb3fa3cb56b6a91886d
set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v2.0.0.tar.gz)
set(UNIBILIUM_SHA256 78997d38d4c8177c60d3d0c1aa8c53fd0806eb21825b7b335b1768d7116bc1c1)
-if(WIN32)
-set(LIBTERMKEY_URL https://github.com/equalsraf/libtermkey/archive/tb-windows.zip)
-set(LIBTERMKEY_SHA256 c81e33e38662b151a49847ff4feef4f8c4b2a66f3e159a28b575cbc9bcd8ffea)
-else()
set(LIBTERMKEY_URL http://www.leonerd.org.uk/code/libtermkey/libtermkey-0.20.tar.gz)
set(LIBTERMKEY_SHA256 6c0d87c94ab9915e76ecd313baec08dedf3bd56de83743d9aa923a081935d2f5)
-endif()
set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz)
set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796)
diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake
index b5cd0c4ca6..8147c47e1e 100644
--- a/third-party/cmake/BuildLibtermkey.cmake
+++ b/third-party/cmake/BuildLibtermkey.cmake
@@ -11,14 +11,22 @@ ExternalProject_Add(libtermkey
-DTARGET=libtermkey
-DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
- CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libtermkey
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- # Pass toolchain
- -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN}
- -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
- # Hack to avoid -rdynamic in Mingw
- -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS=""
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ PATCH_COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey init
+ COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey apply --ignore-whitespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/patches/libtermkey-Add-support-for-Windows.patch
+ CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/libtermkeyCMakeLists.txt
+ ${DEPS_BUILD_DIR}/src/libtermkey/CMakeLists.txt
+ COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libtermkey
+ -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
+ # Pass toolchain
+ -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ # Hack to avoid -rdynamic in Mingw
+ -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS=""
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -DUNIBILIUM_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include
+ -DUNIBILIUM_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}unibilium${CMAKE_STATIC_LIBRARY_SUFFIX}
BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}
INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE})
else()
diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake
index e65a81bba5..2fda221b12 100644
--- a/third-party/cmake/BuildLuajit.cmake
+++ b/third-party/cmake/BuildLuajit.cmake
@@ -35,10 +35,16 @@ function(BuildLuajit)
INSTALL_COMMAND "${_luajit_INSTALL_COMMAND}")
endfunction()
+if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
+ set(AMD64_ABI "LDFLAGS=-lpthread -lc++abi")
+else()
+ set(AMD64_ABI "")
+endif()
set(INSTALLCMD_UNIX ${MAKE_PRG} CFLAGS=-fPIC
CFLAGS+=-DLUAJIT_DISABLE_JIT
CFLAGS+=-DLUA_USE_APICHECK
CFLAGS+=-DLUA_USE_ASSERT
+ ${AMD64_ABI}
CCDEBUG+=-g
Q=
install)
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index 2a786dd8f3..bc1e989cc2 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -37,9 +37,17 @@ set(LUV_SRC_DIR ${DEPS_BUILD_DIR}/src/luv)
set(LUV_INCLUDE_FLAGS
"-I${DEPS_INSTALL_DIR}/include -I${DEPS_INSTALL_DIR}/include/luajit-2.0")
+# Replace luv default rockspec with the alternate one under the "rockspecs"
+# directory
set(LUV_PATCH_COMMAND
- ${CMAKE_COMMAND} -DLUV_SRC_DIR=${LUV_SRC_DIR}
- -P ${PROJECT_SOURCE_DIR}/cmake/PatchLuv.cmake)
+ ${CMAKE_COMMAND} -E copy_directory ${LUV_SRC_DIR}/rockspecs ${LUV_SRC_DIR})
+if(MINGW)
+ set(LUV_PATCH_COMMAND
+ ${LUV_PATCH_COMMAND}
+ COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} init
+ COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} apply --ignore-whitespace
+ ${CMAKE_CURRENT_SOURCE_DIR}/patches/luv-Add-missing-definitions-for-MinGW.patch)
+endif()
set(LUV_CONFIGURE_COMMAND_COMMON
${CMAKE_COMMAND} ${LUV_SRC_DIR}
diff --git a/third-party/cmake/PatchLuv.cmake b/third-party/cmake/PatchLuv.cmake
deleted file mode 100644
index 96595a2f30..0000000000
--- a/third-party/cmake/PatchLuv.cmake
+++ /dev/null
@@ -1,29 +0,0 @@
-# replace luv default rockspec with the alternate one under the "rockspecs"
-# directory
-file(GLOB LUV_ROCKSPEC RELATIVE ${LUV_SRC_DIR} ${LUV_SRC_DIR}/*.rockspec)
-file(RENAME ${LUV_SRC_DIR}/rockspecs/${LUV_ROCKSPEC} ${LUV_SRC_DIR}/${LUV_ROCKSPEC})
-
-# Some versions of mingw are missing defines required by luv dns module, add
-# them now
-set(LUV_SRC_DNS_C_DEFS
-"#ifndef AI_NUMERICSERV
-# define AI_NUMERICSERV 0x0008
-#endif
-#ifndef AI_ALL
-# define AI_ALL 0x00000100
-#endif
-#ifndef AI_ADDRCONFIG
-# define AI_ADDRCONFIG 0x00000400
-#endif
-#ifndef AI_V4MAPPED
-# define AI_V4MAPPED 0x00000800
-#endif")
-
-file(READ ${LUV_SRC_DIR}/src/dns.c LUV_SRC_DNS_C)
-string(REPLACE
- "\n#include <netdb.h>"
- "\n#include <netdb.h>\n#else\n${LUV_SRC_DNS_C_DEFS}"
- LUV_SRC_DNS_C_PATCHED
- "${LUV_SRC_DNS_C}")
-file(WRITE ${LUV_SRC_DIR}/src/dns.c "${LUV_SRC_DNS_C_PATCHED}")
-
diff --git a/third-party/cmake/libtermkeyCMakeLists.txt b/third-party/cmake/libtermkeyCMakeLists.txt
new file mode 100644
index 0000000000..cb57631c1c
--- /dev/null
+++ b/third-party/cmake/libtermkeyCMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 2.8.7)
+project(libtermkey)
+
+add_definitions(-D _CRT_SECURE_NO_WARNINGS)
+add_definitions(-DHAVE_UNIBILIUM)
+if(NOT MSVC)
+ add_definitions(-std=c99)
+endif()
+
+include_directories(${PROJECT_BINARY_DIR}/t)
+include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
+
+add_library(termkey termkey.c driver-csi.c driver-ti.c)
+set_target_properties(termkey PROPERTIES
+ PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/termkey.h)
+target_link_libraries(termkey ${UNIBILIUM_LIBRARIES})
+
+include(GNUInstallDirs)
+install(TARGETS termkey
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+enable_testing()
+file(GLOB TESTSOURCES "t/[0-9]*.c")
+foreach(f ${TESTSOURCES})
+ get_filename_component(t ${f} NAME_WE)
+ if(${t} STREQUAL 05read)
+ continue()
+ endif()
+
+ add_executable("test_${t}" ${f} t/taplib.c)
+ target_link_libraries("test_${t}" termkey)
+ add_test("${t}" "test_${t}")
+endforeach()
diff --git a/third-party/patches/libtermkey-Add-support-for-Windows.patch b/third-party/patches/libtermkey-Add-support-for-Windows.patch
new file mode 100644
index 0000000000..b839e94d05
--- /dev/null
+++ b/third-party/patches/libtermkey-Add-support-for-Windows.patch
@@ -0,0 +1,170 @@
+From fbe91a958816d85fa93665eb8f7a7a8e05eb9650 Mon Sep 17 00:00:00 2001
+From: Rui Abreu Ferreira <raf-ep@gmx.com>
+Date: Tue, 5 Apr 2016 00:12:41 +0100
+Subject: [PATCH] Add support for Windows
+
+Ported termkey for windows.
+
+- The TERMKEY_FLAG_NOTERMIOS is ignore in Windows, since there is no termios.
+- The termkey_waitkey() function is not implemented in windows, since there
+ is no poll() alternative.
+- The CMake recipe only supports unibilium, not curses.
+---
+ driver-ti.c | 8 +++++++-
+ termkey-internal.h | 11 ++++++++++-
+ termkey.c | 22 ++++++++++++++++++----
+ 3 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/driver-ti.c b/driver-ti.c
+index e673ab7..f5f8052 100644
+--- a/driver-ti.c
++++ b/driver-ti.c
+@@ -17,7 +17,9 @@
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <string.h>
+-#include <unistd.h>
++#ifndef _WIN32
++# include <unistd.h>
++#endif
+ #include <sys/types.h>
+ #include <sys/stat.h>
+
+@@ -338,8 +340,10 @@ static int start_driver(TermKey *tk, void *info)
+ if(fstat(tk->fd, &statbuf) == -1)
+ return 0;
+
++#ifndef _WIN32
+ if(S_ISFIFO(statbuf.st_mode))
+ return 1;
++#endif
+
+ // Can't call putp or tputs because they suck and don't give us fd control
+ len = strlen(start_string);
+@@ -367,8 +371,10 @@ static int stop_driver(TermKey *tk, void *info)
+ if(fstat(tk->fd, &statbuf) == -1)
+ return 0;
+
++#ifndef _WIN32
+ if(S_ISFIFO(statbuf.st_mode))
+ return 1;
++#endif
+
+ /* The terminfo database will contain keys in application cursor key mode.
+ * We may need to enable that mode
+diff --git a/termkey-internal.h b/termkey-internal.h
+index 52829b3..b796729 100644
+--- a/termkey-internal.h
++++ b/termkey-internal.h
+@@ -4,7 +4,14 @@
+ #include "termkey.h"
+
+ #include <stdint.h>
+-#include <termios.h>
++#ifndef _WIN32
++# include <termios.h>
++#endif
++
++#ifdef _MSC_VER
++#include <BaseTsd.h>
++typedef SSIZE_T ssize_t;
++#endif
+
+ struct TermKeyDriver
+ {
+@@ -41,8 +48,10 @@ struct TermKey {
+ size_t hightide; /* Position beyond buffstart at which peekkey() should next start
+ * normally 0, but see also termkey_interpret_csi */
+
++#ifndef _WIN32
+ struct termios restore_termios;
+ char restore_termios_valid;
++#endif
+
+ TermKey_Terminfo_Getstr_Hook *ti_getstr_hook;
+ void *ti_getstr_hook_data;
+diff --git a/termkey.c b/termkey.c
+index 2f01f3a..145b99f 100644
+--- a/termkey.c
++++ b/termkey.c
+@@ -3,14 +3,20 @@
+
+ #include <ctype.h>
+ #include <errno.h>
+-#include <poll.h>
+-#include <unistd.h>
++#ifndef _WIN32
++# include <poll.h>
++# include <unistd.h>
++# include <strings.h>
++#endif
+ #include <string.h>
+-#include <strings.h>
+
+ #include <stdio.h>
+
+-#define strcaseeq(a,b) (strcasecmp(a,b) == 0)
++#ifdef _MSC_VER
++# define strcaseeq(a,b) (_stricmp(a,b) == 0)
++#else
++# define strcaseeq(a,b) (strcasecmp(a,b) == 0)
++#endif
+
+ void termkey_check_version(int major, int minor)
+ {
+@@ -282,7 +288,9 @@ static TermKey *termkey_alloc(void)
+ tk->buffsize = 256; /* bytes */
+ tk->hightide = 0;
+
++#ifndef _WIN32
+ tk->restore_termios_valid = 0;
++#endif
+
+ tk->ti_getstr_hook = NULL;
+ tk->ti_getstr_hook_data = NULL;
+@@ -483,6 +491,7 @@ int termkey_start(TermKey *tk)
+ if(tk->is_started)
+ return 1;
+
++#ifndef _WIN32
+ if(tk->fd != -1 && !(tk->flags & TERMKEY_FLAG_NOTERMIOS)) {
+ struct termios termios;
+ if(tcgetattr(tk->fd, &termios) == 0) {
+@@ -517,6 +526,7 @@ int termkey_start(TermKey *tk)
+ tcsetattr(tk->fd, TCSANOW, &termios);
+ }
+ }
++#endif
+
+ struct TermKeyDriverNode *p;
+ for(p = tk->drivers; p; p = p->next)
+@@ -542,8 +552,10 @@ int termkey_stop(TermKey *tk)
+ if(p->driver->stop_driver)
+ (*p->driver->stop_driver)(tk, p->info);
+
++#ifndef _WIN32
+ if(tk->restore_termios_valid)
+ tcsetattr(tk->fd, TCSANOW, &tk->restore_termios);
++#endif
+
+ tk->is_started = 0;
+
+@@ -1046,6 +1058,7 @@ TermKeyResult termkey_getkey_force(TermKey *tk, TermKeyKey *key)
+ return ret;
+ }
+
++#ifndef _WIN32
+ TermKeyResult termkey_waitkey(TermKey *tk, TermKeyKey *key)
+ {
+ if(tk->fd == -1) {
+@@ -1105,6 +1118,7 @@ retry:
+
+ /* UNREACHABLE */
+ }
++#endif
+
+ TermKeyResult termkey_advisereadable(TermKey *tk)
+ {
+--
+2.16.1.windows.4
+
diff --git a/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch b/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
new file mode 100644
index 0000000000..8954ae21c3
--- /dev/null
+++ b/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
@@ -0,0 +1,24 @@
+diff --git a/src/dns.c b/src/dns.c
+index 8634157..5f36625 100644
+--- a/src/dns.c
++++ b/src/dns.c
+@@ -20,6 +20,19 @@
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netdb.h>
++#elif __MINGW32__
++# ifndef AI_NUMERICSERV
++# define AI_NUMERICSERV 0x0008
++# endif
++# ifndef AI_ALL
++# define AI_ALL 0x00000100
++# endif
++# ifndef AI_ADDRCONFIG
++# define AI_ADDRCONFIG 0x00000400
++# endif
++# ifndef AI_V4MAPPED
++# define AI_V4MAPPED 0x00000800
++# endif
+ #endif
+
+ static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) {