changeset 32949:6e346800670c

Add missing changes
author Christian Brabandt <cb@256bit.org>
date Sun, 20 Aug 2023 22:12:43 +0200
parents eca44effa172
children d415dfae6977
files .github/CODEOWNERS runtime/autoload/dist/ft.vim runtime/autoload/dist/man.vim runtime/doc/builtin.txt runtime/doc/filetype.txt runtime/doc/syntax.txt runtime/filetype.vim runtime/ftplugin/haskell.vim runtime/pack/dist/opt/termdebug/plugin/termdebug.vim src/cmdexpand.c src/ex_getln.c src/if_python3.c src/testdir/test_cmdline.vim src/testdir/test_filetype.vim src/usercmd.c src/version.c
diffstat 16 files changed, 224 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -192,6 +192,7 @@ runtime/ftplugin/ps1xml.vim		@heaths
 runtime/ftplugin/pymanifest.vim		@ObserverOfTime
 runtime/ftplugin/python.vim		@tpict
 runtime/ftplugin/qb64.vim		@dkearns
+runtime/ftplugin/qml.vim        @ChaseKnowlden
 runtime/ftplugin/r.vim			@jalvesaq
 runtime/ftplugin/racket.vim		@benknoble
 runtime/ftplugin/readline.vim		@dkearns
@@ -284,6 +285,7 @@ runtime/indent/postscr.vim		@mrdubya
 runtime/indent/prolog.vim		@dkearns
 runtime/indent/ps1.vim			@heaths
 runtime/indent/qb64.vim			@dkearns
+runtime/indent/qml.vim          @ChaseKnowlden
 runtime/indent/r.vim			@jalvesaq
 runtime/indent/racket.vim		@benknoble
 runtime/indent/rapid.vim		@KnoP-01
@@ -443,6 +445,7 @@ runtime/syntax/ps1xml.vim		@heaths
 runtime/syntax/psl.vim			@danielkho
 runtime/syntax/pymanifest.vim		@ObserverOfTime
 runtime/syntax/qb64.vim			@dkearns
+runtime/syntax/qml.vim          @ChaseKnowlden
 runtime/syntax/r.vim			@jalvesaq
 runtime/syntax/racket.vim		@benknoble
 runtime/syntax/raml.vim			@in3d
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -287,6 +287,37 @@ export def FTe()
   endif
 enddef
 
+def IsForth(): bool
+  var first_line = nextnonblank(1)
+
+  # SwiftForth block comment (line is usually filled with '-' or '=') or
+  # OPTIONAL (sometimes precedes the header comment)
+  if getline(first_line) =~? '^\%({\%(\s\|$\)\|OPTIONAL\s\)'
+    return true
+  endif
+
+  var n = first_line
+  while n < 100 && n <= line("$")
+    # Forth comments and colon definitions
+    if getline(n) =~ '^[:(\\] '
+      return true
+    endif
+    n += 1
+  endwhile
+  return false
+enddef
+
+# Distinguish between Forth and Fortran
+export def FTf()
+  if exists("g:filetype_f")
+    exe "setf " .. g:filetype_f
+  elseif IsForth()
+    setf forth
+  else
+    setf fortran
+  endif
+enddef
+
 export def FTfrm()
   if exists("g:filetype_frm")
     exe "setf " .. g:filetype_frm
@@ -302,21 +333,13 @@ export def FTfrm()
   endif
 enddef
 
-# Distinguish between Forth and F#.
-# Provided by Doug Kearns.
+# Distinguish between Forth and F#
 export def FTfs()
   if exists("g:filetype_fs")
     exe "setf " .. g:filetype_fs
+  elseif IsForth()
+    setf forth
   else
-    var n = 1
-    while n < 100 && n <= line("$")
-      # Forth comments and colon definitions
-      if getline(n) =~ "^[:(\\\\] "
-        setf forth
-        return
-      endif
-      n += 1
-    endwhile
     setf fsharp
   endif
 enddef
--- a/runtime/autoload/dist/man.vim
+++ b/runtime/autoload/dist/man.vim
@@ -196,7 +196,7 @@ func dist#man#GetPage(cmdmods, ...)
 
   " Emulate piping the buffer through the "col -b" command.
   " Ref: https://github.com/vim/vim/issues/12301
-  silent! keepjumps keeppatterns %s/(.)\ze?//ge
+  silent! keepjumps keeppatterns %s/\v(.)\b\ze\1?//ge
 
   if unsetwidth
     let $MANWIDTH = ''
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -3551,6 +3551,8 @@ getcompletion({pat}, {type} [, {filtered
 		cmdline		|cmdline-completion| result
 		compiler	compilers
 		cscope		|:cscope| suboptions
+		custom,{func}	custom completion, defined via {func}
+		customlist,{func} custom completion, defined via {func}
 		diff_buffer     |:diffget| and |:diffput| completion
 		dir		directory names
 		environment	environment variable names
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -146,6 +146,7 @@ variables can be used to overrule the fi
 	*.cls		g:filetype_cls
 	*.csh		g:filetype_csh	|ft-csh-syntax|
 	*.dat		g:filetype_dat
+	*.f		g:filetype_f	|ft-forth-syntax|
 	*.frm		g:filetype_frm	|ft-form-syntax|
 	*.fs		g:filetype_fs	|ft-forth-syntax|
 	*.i		g:filetype_i	|ft-progress-syntax|
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -1579,9 +1579,10 @@ example, FORM files, use this in your st
 
 FORTH						*forth.vim* *ft-forth-syntax*
 
-Files matching "*.fs" could be F# or Forth.  If the automatic detection
-doesn't work for you, or you don't edit F# at all, use this in your
-startup vimrc: >
+Files matching "*.f" could be Fortran or Forth and those matching "*.fs" could
+be F# or Forth.  If the automatic detection doesn't work for you, or you don't
+edit F# or Fortran at all, use this in your startup vimrc: >
+   :let filetype_f  = "forth"
    :let filetype_fs = "forth"
 
 
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -724,16 +724,19 @@ au BufNewFile,BufRead auto.master		setf 
 au BufNewFile,BufRead *.mas,*.master		setf master
 
 " Forth
-au BufNewFile,BufRead *.ft,*.fth		setf forth
+au BufNewFile,BufRead *.ft,*.fth,*.4th		setf forth
 
 " Reva Forth
 au BufNewFile,BufRead *.frt			setf reva
 
 " Fortran
 if has("fname_case")
-  au BufNewFile,BufRead *.F,*.FOR,*.FPP,*.FTN,*.F77,*.F90,*.F95,*.F03,*.F08	 setf fortran
+  au BufNewFile,BufRead *.F,*.FOR,*.FPP,*.FTN,*.F77,*.F90,*.F95,*.F03,*.F08	setf fortran
 endif
-au BufNewFile,BufRead   *.f,*.for,*.fortran,*.fpp,*.ftn,*.f77,*.f90,*.f95,*.f03,*.f08  setf fortran
+au BufNewFile,BufRead *.for,*.fortran,*.fpp,*.ftn,*.f77,*.f90,*.f95,*.f03,*.f08	setf fortran
+
+" Fortran or Forth
+au BufNewFile,BufRead *.f			call dist#ft#FTf()
 
 " Framescript
 au BufNewFile,BufRead *.fsl			setf framescript
@@ -1708,6 +1711,9 @@ au BufNewFile,BufRead *.ptl,*.pyi,SConst
 " QL
 au BufRead,BufNewFile *.ql,*.qll		setf ql
 
+" QML
+au BufRead,BufNewFile *.qml,*.qbs			setf qml
+
 " QMLdir
 au BufRead,BufNewFile qmldir			setf qmldir
 
--- a/runtime/ftplugin/haskell.vim
+++ b/runtime/ftplugin/haskell.vim
@@ -17,6 +17,7 @@ let b:undo_ftplugin = "setl com< cms< fo
 setlocal comments=s1fl:{-,mb:-,ex:-},:-- commentstring=--\ %s
 setlocal formatoptions-=t formatoptions+=croql
 setlocal omnifunc=haskellcomplete#Complete
+setlocal iskeyword+='
 
 let &cpo = s:cpo_save
 unlet s:cpo_save
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -122,6 +122,10 @@ func s:GetCommand()
   return type(cmd) == v:t_list ? copy(cmd) : [cmd]
 endfunc
 
+func s:Echoerr(msg)
+  echohl ErrorMsg | echom '[termdebug] ' .. a:msg | echohl None
+endfunc
+
 func s:StartDebug(bang, ...)
   " First argument is the command to debug, second core file or process ID.
   call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang})
@@ -134,12 +138,12 @@ endfunc
 
 func s:StartDebug_internal(dict)
   if exists('s:gdbwin')
-    echoerr 'Terminal debugger already running, cannot run two'
+    call s:Echoerr('Terminal debugger already running, cannot run two')
     return
   endif
   let gdbcmd = s:GetCommand()
   if !executable(gdbcmd[0])
-    echoerr 'Cannot execute debugger program "' .. gdbcmd[0] .. '"'
+    call s:Echoerr('Cannot execute debugger program "' .. gdbcmd[0] .. '"')
     return
   endif
 
@@ -238,7 +242,7 @@ endfunc
 func s:CheckGdbRunning()
   let gdbproc = term_getjob(s:gdbbuf)
   if gdbproc == v:null || job_status(gdbproc) !=# 'run'
-    echoerr string(s:GetCommand()[0]) . ' exited unexpectedly'
+    call s:Echoerr(string(s:GetCommand()[0]) . ' exited unexpectedly')
     call s:CloseBuffers()
     return ''
   endif
@@ -252,7 +256,7 @@ func s:StartDebug_term(dict)
 	\ 'vertical': s:vertical,
 	\ })
   if s:ptybuf == 0
-    echoerr 'Failed to open the program terminal window'
+    call s:Echoerr('Failed to open the program terminal window')
     return
   endif
   let pty = job_info(term_getjob(s:ptybuf))['tty_out']
@@ -274,7 +278,7 @@ func s:StartDebug_term(dict)
 	\ 'hidden': 1,
 	\ })
   if s:commbuf == 0
-    echoerr 'Failed to open the communication terminal window'
+    call s:Echoerr('Failed to open the communication terminal window')
     exe 'bwipe! ' . s:ptybuf
     return
   endif
@@ -315,7 +319,7 @@ func s:StartDebug_term(dict)
 	\ 'term_finish': 'close',
 	\ })
   if s:gdbbuf == 0
-    echoerr 'Failed to open the gdb terminal window'
+    call s:Echoerr('Failed to open the gdb terminal window')
     call s:CloseBuffers()
     return
   endif
@@ -367,7 +371,7 @@ func s:StartDebug_term(dict)
         " response can be in the same line or the next line
         let response = line1 . line2
         if response =~ 'Undefined command'
-          echoerr 'Sorry, your gdb is too old, gdb 7.12 is required'
+          call s:Echoerr('Sorry, your gdb is too old, gdb 7.12 is required')
           " CHECKME: possibly send a "server show version" here
           call s:CloseBuffers()
           return
@@ -386,7 +390,7 @@ func s:StartDebug_term(dict)
     endif
     let try_count += 1
     if try_count > 100
-      echoerr 'Cannot check if your gdb works, continuing anyway'
+      call s:Echoerr('Cannot check if your gdb works, continuing anyway')
       break
     endif
     sleep 10m
@@ -445,7 +449,7 @@ func s:StartDebug_prompt(dict)
 	\ 'out_cb': function('s:GdbOutCallback'),
 	\ })
   if job_status(s:gdbjob) != "run"
-    echoerr 'Failed to start gdb'
+    call s:Echoerr('Failed to start gdb')
     exe 'bwipe! ' . s:promptbuf
     return
   endif
@@ -464,7 +468,7 @@ func s:StartDebug_prompt(dict)
 	  \ 'term_name': 'debugged program',
 	  \ })
     if s:ptybuf == 0
-      echoerr 'Failed to open the program terminal window'
+      call s:Echoerr('Failed to open the program terminal window')
       call job_stop(s:gdbjob)
       return
     endif
@@ -600,7 +604,7 @@ func s:PromptInterrupt()
     " Using job_stop() does not work on MS-Windows, need to send SIGTRAP to
     " the debugger program so that gdb responds again.
     if s:pid == 0
-      echoerr 'Cannot interrupt gdb, did not find a process ID'
+      call s:Echoerr('Cannot interrupt gdb, did not find a process ID')
     else
       call debugbreak(s:pid)
     endif
@@ -651,7 +655,7 @@ endfunc
 " - change \\ to \
 func s:DecodeMessage(quotedText, literal)
   if a:quotedText[0] != '"'
-    echoerr 'DecodeMessage(): missing quote in ' . a:quotedText
+    call s:Echoerr('DecodeMessage(): missing quote in ' . a:quotedText)
     return
   endif
   let msg = a:quotedText
@@ -1154,7 +1158,7 @@ func s:ClearBreakpoint()
       endif
       echomsg 'Breakpoint ' . id . ' cleared from line ' . lnum . '.'
     else
-      echoerr 'Internal error trying to remove breakpoint at line ' . lnum . '!'
+      call s:Echoerr('Internal error trying to remove breakpoint at line ' . lnum . '!')
     endif
   else
     echomsg 'No breakpoint to remove at line ' . lnum . '.'
@@ -1305,7 +1309,7 @@ func s:HandleError(msg)
     return
   endif
   let msgVal = substitute(a:msg, '.*msg="\(.*\)"', '\1', '')
-  echoerr substitute(msgVal, '\\"', '"', 'g')
+  call s:Echoerr(substitute(msgVal, '\\"', '"', 'g'))
 endfunc
 
 func s:GotoSourcewinOrCreateIt()
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -4022,6 +4022,7 @@ f_getcompletion(typval_T *argvars, typva
     {
 	xpc.xp_pattern = pat;
 	xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+        xpc.xp_line = pat;
 
 	xpc.xp_context = cmdcomplete_str_to_type(type);
 	if (xpc.xp_context == EXPAND_NOTHING)
@@ -4030,6 +4031,30 @@ f_getcompletion(typval_T *argvars, typva
 	    return;
 	}
 
+	if (xpc.xp_context == EXPAND_USER_DEFINED)
+	{
+            // Must be "custom,funcname" pattern
+            if (STRNCMP(type, "custom,", 7) != 0)
+            {
+                semsg(_(e_invalid_argument_str), type);
+                return;
+            }
+
+            xpc.xp_arg = type + 7;
+	}
+
+	if (xpc.xp_context == EXPAND_USER_LIST)
+	{
+            // Must be "customlist,funcname" pattern
+            if (STRNCMP(type, "customlist,", 11) != 0)
+            {
+                semsg(_(e_invalid_argument_str), type);
+                return;
+            }
+
+            xpc.xp_arg = type + 11;
+	}
+
 # if defined(FEAT_MENU)
 	if (xpc.xp_context == EXPAND_MENUS)
 	{
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -4152,6 +4152,7 @@ get_cmdline_str(void)
 get_cmdline_completion(void)
 {
     cmdline_info_T *p;
+    char_u	*buffer;
 
     if (cmdline_star > 0)
 	return NULL;
@@ -4165,10 +4166,19 @@ get_cmdline_completion(void)
 	return NULL;
 
     char_u *cmd_compl = cmdcomplete_type_to_str(p->xpc->xp_context);
-    if (cmd_compl != NULL)
-	return vim_strsave(cmd_compl);
-
-    return NULL;
+    if (cmd_compl == NULL)
+        return NULL;
+
+    if (p->xpc->xp_context == EXPAND_USER_LIST || p->xpc->xp_context == EXPAND_USER_DEFINED)
+    {
+	buffer = alloc(STRLEN(cmd_compl) + STRLEN(p->xpc->xp_arg) + 2);
+	if (buffer == NULL)
+	    return NULL;
+	sprintf((char *)buffer, "%s,%s", cmd_compl, p->xpc->xp_arg);
+	return buffer;
+    }
+
+    return vim_strsave(cmd_compl);
 }
 
 /*
index 9d44b7a196fb57ab65afc931a6bc5e53ed0f8370..c6d1acc198c9bd0434cb7d991c44f0d9f0ec2765
GIT binary patch
literal 65229
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
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -3511,4 +3511,42 @@ func Test_getcompletion_usercmd()
   delcom TestCompletion
 endfunc
 
+func Test_custom_completion()
+  func CustomComplete1(lead, line, pos)
+    return "a\nb\nc"
+  endfunc
+  func CustomComplete2(lead, line, pos)
+    return ['a', 'b']->filter({ _, val -> val->stridx(a:lead) == 0 })
+  endfunc
+  func Check_custom_completion()
+    call assert_equal('custom,CustomComplete1', getcmdcompltype())
+    return ''
+  endfunc
+  func Check_customlist_completion()
+    call assert_equal('customlist,CustomComplete2', getcmdcompltype())
+    return ''
+  endfunc
+
+  command -nargs=1 -complete=custom,CustomComplete1 Test1 echo
+  command -nargs=1 -complete=customlist,CustomComplete2 Test2 echo
+
+  call feedkeys(":Test1 \<C-R>=Check_custom_completion()\<CR>\<Esc>", "xt")
+  call feedkeys(":Test2 \<C-R>=Check_customlist_completion()\<CR>\<Esc>", "xt")
+
+  call assert_fails("call getcompletion('', 'custom')", 'E475:')
+  call assert_fails("call getcompletion('', 'customlist')", 'E475:')
+
+  call assert_equal(getcompletion('', 'custom,CustomComplete1'), ['a', 'b', 'c'])
+  call assert_equal(getcompletion('', 'customlist,CustomComplete2'), ['a', 'b'])
+  call assert_equal(getcompletion('b', 'customlist,CustomComplete2'), ['b'])
+
+  delcom Test1
+  delcom Test2
+
+  delfunc CustomComplete1
+  delfunc CustomComplete2
+  delfunc Check_custom_completion
+  delfunc Check_customlist_completion
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_filetype.vim
+++ b/src/testdir/test_filetype.vim
@@ -246,7 +246,7 @@ def s:GetFilenameChecks(): dict<list<str
     fish: ['file.fish'],
     focexec: ['file.fex', 'file.focexec'],
     form: ['file.frm'],
-    forth: ['file.ft', 'file.fth'],
+    forth: ['file.ft', 'file.fth', 'file.4th'],
     fortran: ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'],
     fpcmake: ['file.fpc'],
     framescript: ['file.fsl'],
@@ -551,6 +551,7 @@ def s:GetFilenameChecks(): dict<list<str
     pyrex: ['file.pyx', 'file.pxd'],
     python: ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
     ql: ['file.ql', 'file.qll'],
+    qml: ['file.qml', 'file.qbs'],
     qmldir: ['qmldir'],
     quake: ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'],
     quarto: ['file.qmd'],
@@ -1264,6 +1265,54 @@ func Test_ex_file()
   filetype off
 endfunc
 
+func Test_f_file()
+  filetype on
+
+  call writefile(['looks like Fortran'], 'Xfile.f', 'D')
+  split Xfile.f
+  call assert_equal('fortran', &filetype)
+  bwipe!
+
+  let g:filetype_f = 'forth'
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+  unlet g:filetype_f
+
+  " Test dist#ft#FTf()
+
+  " Forth
+
+  call writefile(['( Forth inline comment )'], 'Xfile.f')
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  call writefile(['\ Forth line comment'], 'Xfile.f')
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  call writefile([': squared ( n -- n^2 )', 'dup * ;'], 'Xfile.f')
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  " SwiftForth
+
+  call writefile(['{ ================', 'Header comment', '================ }'], 'Xfile.f')
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  call writefile(['OPTIONAL Maybe Descriptive text'], 'Xfile.f')
+  split Xfile.f
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  filetype off
+endfunc
+
 func Test_foam_file()
   filetype on
   call assert_true(mkdir('0', 'pR'))
@@ -1354,7 +1403,7 @@ func Test_fs_file()
 
   " Test dist#ft#FTfs()
 
-  " Forth (Gforth)
+  " Forth
 
   call writefile(['( Forth inline comment )'], 'Xfile.fs')
   split Xfile.fs
@@ -1371,6 +1420,18 @@ func Test_fs_file()
   call assert_equal('forth', &filetype)
   bwipe!
 
+  " SwiftForth
+
+  call writefile(['{ ================', 'Header comment', '================ }'], 'Xfile.fs')
+  split Xfile.fs
+  call assert_equal('forth', &filetype)
+  bwipe!
+
+  call writefile(['OPTIONAL Maybe Descriptive text'], 'Xfile.fs')
+  split Xfile.fs
+  call assert_equal('forth', &filetype)
+  bwipe!
+
   filetype off
 endfunc
 
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -481,6 +481,11 @@ cmdcomplete_str_to_type(char_u *complete
 {
     int i;
 
+    if (STRNCMP(complete_str, "custom,", 7) == 0)
+	return EXPAND_USER_DEFINED;
+    if (STRNCMP(complete_str, "customlist,", 11) == 0)
+	return EXPAND_USER_LIST;
+
     for (i = 0; command_complete[i].expand != 0; ++i)
 	if (STRCMP(complete_str, command_complete[i].name) == 0)
 	    return command_complete[i].expand;
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,10 @@ static int included_patches[] =
 /**/
     1775,
 /**/
+    1774,
+/**/
+    1773,
+/**/
     1772,
 /**/
     1771,
@@ -716,6 +720,8 @@ static int included_patches[] =
 /**/
     1767,
 /**/
+    1766,
+/**/
     1765,
 /**/
     1764,