This commit is contained in:
Justin M. Keyes 2024-12-18 15:59:07 -08:00 committed by GitHub
commit f0a2a40744
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 440 additions and 429 deletions

View File

@ -167,13 +167,15 @@ function! s:Spawn(server_cmd, client_cmd, server_addr, reconnect)
if type(a:server_cmd) == type('') if type(a:server_cmd) == type('')
" spawn gdbserver in a vertical split " spawn gdbserver in a vertical split
let server = s:GdbServer.new(gdb) let server = s:GdbServer.new(gdb)
vsp | enew | let gdb._server_id = termopen(a:server_cmd, server) server.term = v:true
vsp | enew | let gdb._server_id = jobstart(a:server_cmd, server)
let gdb._jump_window = 2 let gdb._jump_window = 2
let gdb._server_buf = bufnr('%') let gdb._server_buf = bufnr('%')
endif endif
" go to the bottom window and spawn gdb client " go to the bottom window and spawn gdb client
wincmd j wincmd j
enew | let gdb._client_id = termopen(a:client_cmd, gdb) gdb.term = v:true
enew | let gdb._client_id = jobstart(a:client_cmd, gdb)
let gdb._client_buf = bufnr('%') let gdb._client_buf = bufnr('%')
tnoremap <silent> <f8> <c-\><c-n>:GdbContinue<cr>i tnoremap <silent> <f8> <c-\><c-n>:GdbContinue<cr>i
tnoremap <silent> <f10> <c-\><c-n>:GdbNext<cr>i tnoremap <silent> <f10> <c-\><c-n>:GdbNext<cr>i

View File

@ -2170,12 +2170,12 @@ nvim_buf_call({buffer}, {fun}) *nvim_buf_call()*
This temporarily switches current buffer to "buffer". If the current This temporarily switches current buffer to "buffer". If the current
window already shows "buffer", the window is not switched. If a window window already shows "buffer", the window is not switched. If a window
inside the current tabpage (including a float) already shows the buffer, inside the current tabpage (including a float) already shows the buffer,
then one of these windows will be set as current window temporarily. then one of those windows will be set as current window temporarily.
Otherwise a temporary scratch window (called the "autocmd window" for Otherwise a temporary scratch window (called the "autocmd window" for
historical reasons) will be used. historical reasons) will be used.
This is useful e.g. to call Vimscript functions that only work with the This is useful e.g. to call Vimscript functions that only work with the
current buffer/window currently, like |termopen()|. current buffer/window currently, like `jobstart(…, {'term': v:true})`.
Attributes: ~ Attributes: ~
Lua |vim.api| only Lua |vim.api| only

View File

@ -5309,7 +5309,7 @@ jobresize({job}, {width}, {height}) *jobresize()*
(`any`) (`any`)
jobstart({cmd} [, {opts}]) *jobstart()* jobstart({cmd} [, {opts}]) *jobstart()*
Note: Prefer |vim.system()| in Lua (unless using the `pty` option). Note: Prefer |vim.system()| in Lua (unless using `rpc`, `pty`, or `term`).
Spawns {cmd} as a job. Spawns {cmd} as a job.
If {cmd} is a List it runs directly (no 'shell'). If {cmd} is a List it runs directly (no 'shell').
@ -5383,6 +5383,10 @@ jobstart({cmd} [, {opts}]) *jobstart()*
stdin: (string) Either "pipe" (default) to connect the stdin: (string) Either "pipe" (default) to connect the
job's stdin to a channel or "null" to disconnect job's stdin to a channel or "null" to disconnect
stdin. stdin.
term: (boolean) Spawns {cmd} in a new pseudo-terminal session
connected to the current (unmodified) buffer. Implies "pty".
Default "height" and "width" are set to the current window
dimensions. |jobstart()|. Defaults $TERM to "xterm-256color".
width: (number) Width of the `pty` terminal. width: (number) Width of the `pty` terminal.
{opts} is passed as |self| dictionary to the callback; the {opts} is passed as |self| dictionary to the callback; the
@ -11168,28 +11172,6 @@ tempname() *tempname()*
Return: ~ Return: ~
(`string`) (`string`)
termopen({cmd} [, {opts}]) *termopen()*
Spawns {cmd} in a new pseudo-terminal session connected
to the current (unmodified) buffer. Parameters and behavior
are the same as |jobstart()| except "pty", "width", "height",
and "TERM" are ignored: "height" and "width" are taken from
the current window. Note that termopen() implies a "pty" arg
to jobstart(), and thus has the implications documented at
|jobstart()|.
Returns the same values as jobstart().
Terminal environment is initialized as in |jobstart-env|,
except $TERM is set to "xterm-256color". Full behavior is
described in |terminal|.
Parameters: ~
• {cmd} (`string|string[]`)
• {opts} (`table?`)
Return: ~
(`integer`)
test_garbagecollect_now() *test_garbagecollect_now()* test_garbagecollect_now() *test_garbagecollect_now()*
Like |garbagecollect()|, but executed right away. This must Like |garbagecollect()|, but executed right away. This must
only be called directly to avoid any structure to exist only be called directly to avoid any structure to exist

View File

@ -20,8 +20,8 @@ There are several ways to open a channel:
2. Through stdin, stdout and stderr of a process spawned by |jobstart()|. 2. Through stdin, stdout and stderr of a process spawned by |jobstart()|.
3. Through the PTY master end of a PTY opened with 3. Through the PTY master end of a PTY opened with |nvim_open_term()| or
`jobstart(..., {'pty': v:true})` or |termopen()|. `jobstart(…, {'pty': v:true})`.
4. By connecting to a TCP/IP socket or named pipe with |sockconnect()|. 4. By connecting to a TCP/IP socket or named pipe with |sockconnect()|.

View File

@ -16,49 +16,34 @@ Deprecated features
DEPRECATED IN 0.11 *deprecated-0.11* DEPRECATED IN 0.11 *deprecated-0.11*
API API
- nvim_subscribe() Plugins must maintain their own "multicast" channels list. • nvim_subscribe() Plugins must maintain their own "multicast" channels list.
- nvim_unsubscribe() Plugins must maintain their own "multicast" channels list. • nvim_unsubscribe() Plugins must maintain their own "multicast" channels list.
LUA
- vim.region() Use |getregionpos()| instead.
- *vim.highlight* Renamed to |vim.hl|.
- vim.validate(opts: table) Use form 1. See |vim.validate()|.
DIAGNOSTICS DIAGNOSTICS
- *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count=1, float=true}` instead. • *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count=1, float=true}` instead.
- *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count=-1, float=true}` instead. • *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count=-1, float=true}` instead.
- *vim.diagnostic.get_next_pos()* • *vim.diagnostic.get_next_pos()* Use the "lnum" and "col" fields from the
Use the "lnum" and "col" fields from the return value of return value of |vim.diagnostic.get_next()| instead.
|vim.diagnostic.get_next()| instead. • *vim.diagnostic.get_prev_pos()* Use the "lnum" and "col" fields from the
- *vim.diagnostic.get_prev_pos()* return value of |vim.diagnostic.get_prev()| instead.
Use the "lnum" and "col" fields from the return value of • The "win_id" parameter used by various functions is deprecated in favor of
|vim.diagnostic.get_prev()| instead.
- The "win_id" parameter used by various functions is deprecated in favor of
"winid" |winid| "winid" |winid|
- The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to • |vim.diagnostic.JumpOpts| renamed its "cursor_position" field to "pos".
"pos"
HIGHLIGHTS HIGHLIGHTS
• *TermCursorNC* As of Nvim 0.11, unfocused |terminal| windows no • *TermCursorNC* Unfocused |terminal| windows do not have a cursor.
longer have any cursor.
TREESITTER
• *TSNode:child_containing_descendant()* Use
|TSNode:child_with_descendant()| instead; it is identical except that it can
return the descendant itself.
LSP LSP
• *vim.lsp.util.jump_to_location* Use |vim.lsp.util.show_document()| with • *vim.lsp.util.jump_to_location* Use |vim.lsp.util.show_document()| with
`{focus=true}` instead. `{focus=true}` instead.
• *vim.lsp.buf.execute_command* Use |Client:exec_cmd()| instead. • *vim.lsp.buf.execute_command* Use |Client:exec_cmd()| instead.
• *vim.lsp.buf.completion* Use |vim.lsp.completion.trigger()| instead. • *vim.lsp.buf.completion* Use |vim.lsp.completion.trigger()| instead.
• vim.lsp.buf_request_all The `error` key has been renamed to `err` inside • vim.lsp.buf_request_all The `error` key has been renamed to `err` inside
the result parameter of the handler. the result parameter of the handler.
• *vim.lsp.with()* Pass configuration to equivalent • *vim.lsp.with()* Pass configuration to equivalent
functions in `vim.lsp.buf.*`. functions in `vim.lsp.buf.*`.
• |vim.lsp.handlers| • |vim.lsp.handlers| Does not support client-to-server response handlers. Only
No longer support client to server response handlers. Only server to supports server-to-client requests/notification handlers.
client requests/notification handlers are supported.
• *vim.lsp.handlers.signature_help()* Use |vim.lsp.buf.signature_help()| instead. • *vim.lsp.handlers.signature_help()* Use |vim.lsp.buf.signature_help()| instead.
• `client.request()` Use |Client:request()| instead. • `client.request()` Use |Client:request()| instead.
• `client.request_sync()` Use |Client:request_sync()| instead. • `client.request_sync()` Use |Client:request_sync()| instead.
@ -70,6 +55,18 @@ LSP
• `client.on_attach()` Use |Client:on_attach()| instead. • `client.on_attach()` Use |Client:on_attach()| instead.
• `vim.lsp.start_client()` Use |vim.lsp.start()| instead. • `vim.lsp.start_client()` Use |vim.lsp.start()| instead.
LUA
• vim.region() Use |getregionpos()| instead.
• *vim.highlight* Renamed to |vim.hl|.
• vim.validate(opts: table) Use form 1. See |vim.validate()|.
TREESITTER
• *TSNode:child_containing_descendant()* Use |TSNode:child_with_descendant()|
instead; it is identical except that it can return the descendant itself.
VIMSCRIPT
• *termopen()* Use |jobstart() with `{term: v:true}`.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10* DEPRECATED IN 0.10 *deprecated-0.10*
@ -130,198 +127,198 @@ TREESITTER
DEPRECATED IN 0.9 *deprecated-0.9* DEPRECATED IN 0.9 *deprecated-0.9*
API API
- *nvim_get_hl_by_name()* Use |nvim_get_hl()| instead. *nvim_get_hl_by_name()* Use |nvim_get_hl()| instead.
- *nvim_get_hl_by_id()* Use |nvim_get_hl()| instead. *nvim_get_hl_by_id()* Use |nvim_get_hl()| instead.
TREESITTER TREESITTER
- *vim.treesitter.language.require_language()* Use |vim.treesitter.language.add()| instead. *vim.treesitter.language.require_language()* Use |vim.treesitter.language.add()| instead.
- *vim.treesitter.get_node_at_pos()* Use |vim.treesitter.get_node()| instead. *vim.treesitter.get_node_at_pos()* Use |vim.treesitter.get_node()| instead.
- *vim.treesitter.get_node_at_cursor()* Use |vim.treesitter.get_node()| *vim.treesitter.get_node_at_cursor()* Use |vim.treesitter.get_node()|
and |TSNode:type()| instead. and |TSNode:type()| instead.
• The following top level Treesitter functions have been moved: • The following top level Treesitter functions have been moved:
- *vim.treesitter.inspect_language()* -> |vim.treesitter.language.inspect()| *vim.treesitter.inspect_language()* -> |vim.treesitter.language.inspect()|
- *vim.treesitter.get_query_files()* -> |vim.treesitter.query.get_files()| *vim.treesitter.get_query_files()* -> |vim.treesitter.query.get_files()|
- *vim.treesitter.set_query()* -> |vim.treesitter.query.set()| *vim.treesitter.set_query()* -> |vim.treesitter.query.set()|
- *vim.treesitter.query.set_query()* -> |vim.treesitter.query.set()| *vim.treesitter.query.set_query()* -> |vim.treesitter.query.set()|
- *vim.treesitter.get_query()* -> |vim.treesitter.query.get()| *vim.treesitter.get_query()* -> |vim.treesitter.query.get()|
- *vim.treesitter.query.get_query()* -> |vim.treesitter.query.get()| *vim.treesitter.query.get_query()* -> |vim.treesitter.query.get()|
- *vim.treesitter.parse_query()* -> |vim.treesitter.query.parse()| *vim.treesitter.parse_query()* -> |vim.treesitter.query.parse()|
- *vim.treesitter.query.parse_query()* -> |vim.treesitter.query.parse()| *vim.treesitter.query.parse_query()* -> |vim.treesitter.query.parse()|
- *vim.treesitter.add_predicate()* -> |vim.treesitter.query.add_predicate()| *vim.treesitter.add_predicate()* -> |vim.treesitter.query.add_predicate()|
- *vim.treesitter.add_directive()* -> |vim.treesitter.query.add_directive()| *vim.treesitter.add_directive()* -> |vim.treesitter.query.add_directive()|
- *vim.treesitter.list_predicates()* -> |vim.treesitter.query.list_predicates()| *vim.treesitter.list_predicates()* -> |vim.treesitter.query.list_predicates()|
- *vim.treesitter.list_directives()* -> |vim.treesitter.query.list_directives()| *vim.treesitter.list_directives()* -> |vim.treesitter.query.list_directives()|
- *vim.treesitter.query.get_range()* -> |vim.treesitter.get_range()| *vim.treesitter.query.get_range()* -> |vim.treesitter.get_range()|
- *vim.treesitter.query.get_node_text()* -> |vim.treesitter.get_node_text()| *vim.treesitter.query.get_node_text()* -> |vim.treesitter.get_node_text()|
LUA LUA
- *nvim_exec()* Use |nvim_exec2()| instead. *nvim_exec()* Use |nvim_exec2()| instead.
- *vim.pretty_print()* Use |vim.print()| instead. *vim.pretty_print()* Use |vim.print()| instead.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
DEPRECATED IN 0.8 OR EARLIER DEPRECATED IN 0.8 OR EARLIER
API API
- *nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead. *nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead.
- *nvim_buf_set_virtual_text()* Use |nvim_buf_set_extmark()| instead. *nvim_buf_set_virtual_text()* Use |nvim_buf_set_extmark()| instead.
- *nvim_command_output()* Use |nvim_exec2()| instead. *nvim_command_output()* Use |nvim_exec2()| instead.
- *nvim_execute_lua()* Use |nvim_exec_lua()| instead. *nvim_execute_lua()* Use |nvim_exec_lua()| instead.
- *nvim_get_option_info()* Use |nvim_get_option_info2()| instead. *nvim_get_option_info()* Use |nvim_get_option_info2()| instead.
COMMANDS COMMANDS
- *:rv* *:rviminfo* Deprecated alias to |:rshada| command. *:rv* *:rviminfo* Deprecated alias to |:rshada| command.
- *:wv* *:wviminfo* Deprecated alias to |:wshada| command. *:wv* *:wviminfo* Deprecated alias to |:wshada| command.
ENVIRONMENT VARIABLES ENVIRONMENT VARIABLES
- *$NVIM_LISTEN_ADDRESS* *$NVIM_LISTEN_ADDRESS*
- Deprecated way to: Deprecated way to:
- set the server name (use |--listen| or |serverstart()| instead) set the server name (use |--listen| or |serverstart()| instead)
- get the server name (use |v:servername| instead) get the server name (use |v:servername| instead)
- detect a parent Nvim (use |$NVIM| instead) detect a parent Nvim (use |$NVIM| instead)
- Ignored if --listen is given. Ignored if --listen is given.
- Unset by |terminal| and |jobstart()| unless explicitly given by the "env" Unset by |terminal| and |jobstart()| unless explicitly given by the "env"
option. Example: >vim option. Example: >vim
call jobstart(['foo'], { 'env': { 'NVIM_LISTEN_ADDRESS': v:servername } }) call jobstart(['foo'], { 'env': { 'NVIM_LISTEN_ADDRESS': v:servername } })
< <
EVENTS EVENTS
- *BufCreate* Use |BufAdd| instead. *BufCreate* Use |BufAdd| instead.
- *EncodingChanged* Never fired; 'encoding' is always "utf-8". *EncodingChanged* Never fired; 'encoding' is always "utf-8".
- *FileEncoding* Never fired; equivalent to |EncodingChanged|. *FileEncoding* Never fired; equivalent to |EncodingChanged|.
- *GUIEnter* Never fired; use |UIEnter| instead. *GUIEnter* Never fired; use |UIEnter| instead.
- *GUIFailed* Never fired. *GUIFailed* Never fired.
KEYCODES KEYCODES
- *<MouseDown>* Use <ScrollWheelUp> instead. • *<MouseDown>* Use <ScrollWheelUp> instead.
- *<MouseUp>* Use <ScrollWheelDown> instead. • *<MouseUp>* Use <ScrollWheelDown> instead.
FUNCTIONS
- *buffer_exists()* Obsolete name for |bufexists()|.
- *buffer_name()* Obsolete name for |bufname()|.
- *buffer_number()* Obsolete name for |bufnr()|.
- *file_readable()* Obsolete name for |filereadable()|.
- *highlight_exists()* Obsolete name for |hlexists()|.
- *highlightID()* Obsolete name for |hlID()|.
- *inputdialog()* Use |input()| instead.
- *jobclose()* Obsolete name for |chanclose()|
- *jobsend()* Obsolete name for |chansend()|
- *last_buffer_nr()* Obsolete name for bufnr("$").
- *rpcstart()* Use |jobstart()| with `{'rpc': v:true}` instead.
- *rpcstop()* Use |jobstop()| instead to stop any job, or
`chanclose(id, "rpc")` to close RPC communication
without stopping the job. Use chanclose(id) to close
any socket.
HIGHLIGHTS HIGHLIGHTS
- *hl-VertSplit* Use |hl-WinSeparator| instead. • *hl-VertSplit* Use |hl-WinSeparator| instead.
LSP DIAGNOSTICS LSP DIAGNOSTICS
For each of the functions below, use the corresponding function in For each of the functions below, use the corresponding function in
|vim.diagnostic| instead (unless otherwise noted). For example, use |vim.diagnostic| instead (unless otherwise noted). For example, use
|vim.diagnostic.get()| instead of |vim.lsp.diagnostic.get()|. |vim.diagnostic.get()| instead of |vim.lsp.diagnostic.get()|.
- *vim.lsp.diagnostic.clear()* Use |vim.diagnostic.hide()| instead. • *vim.lsp.diagnostic.clear()* Use |vim.diagnostic.hide()| instead.
- *vim.lsp.diagnostic.disable()* Use |vim.diagnostic.enable()| instead. • *vim.lsp.diagnostic.disable()* Use |vim.diagnostic.enable()| instead.
- *vim.lsp.diagnostic.display()* Use |vim.diagnostic.show()| instead. • *vim.lsp.diagnostic.display()* Use |vim.diagnostic.show()| instead.
- *vim.lsp.diagnostic.enable()* • *vim.lsp.diagnostic.enable()*
- *vim.lsp.diagnostic.get()* • *vim.lsp.diagnostic.get()*
- *vim.lsp.diagnostic.get_all()* Use |vim.diagnostic.get()| instead. • *vim.lsp.diagnostic.get_all()* Use |vim.diagnostic.get()| instead.
- *vim.lsp.diagnostic.get_count()* Use |vim.diagnostic.count()| instead. • *vim.lsp.diagnostic.get_count()* Use |vim.diagnostic.count()| instead.
- *vim.lsp.diagnostic.get_line_diagnostics()* Use |vim.diagnostic.get()| instead. • *vim.lsp.diagnostic.get_line_diagnostics()* Use |vim.diagnostic.get()| instead.
- *vim.lsp.diagnostic.get_next()* *vim.lsp.diagnostic.get_next()*
- *vim.lsp.diagnostic.get_next_pos()* *vim.lsp.diagnostic.get_next_pos()*
- *vim.lsp.diagnostic.get_prev()* *vim.lsp.diagnostic.get_prev()*
- *vim.lsp.diagnostic.get_prev_pos()* *vim.lsp.diagnostic.get_prev_pos()*
- *vim.lsp.diagnostic.get_virtual_text_chunks_for_line()* No replacement. Use *vim.lsp.diagnostic.get_virtual_text_chunks_for_line()* No replacement. Use
options provided by |vim.diagnostic.config()| to customize virtual text. options provided by |vim.diagnostic.config()| to customize virtual text.
- *vim.lsp.diagnostic.goto_next()* *vim.lsp.diagnostic.goto_next()*
- *vim.lsp.diagnostic.goto_prev()* *vim.lsp.diagnostic.goto_prev()*
- *vim.lsp.diagnostic.redraw()* Use |vim.diagnostic.show()| instead. *vim.lsp.diagnostic.redraw()* Use |vim.diagnostic.show()| instead.
- *vim.lsp.diagnostic.reset()* *vim.lsp.diagnostic.reset()*
- *vim.lsp.diagnostic.save()* Use |vim.diagnostic.set()| instead. *vim.lsp.diagnostic.save()* Use |vim.diagnostic.set()| instead.
- *vim.lsp.diagnostic.set_loclist()* Use |vim.diagnostic.setloclist()| instead. *vim.lsp.diagnostic.set_loclist()* Use |vim.diagnostic.setloclist()| instead.
- *vim.lsp.diagnostic.set_qflist()* Use |vim.diagnostic.setqflist()| instead. *vim.lsp.diagnostic.set_qflist()* Use |vim.diagnostic.setqflist()| instead.
- *vim.lsp.diagnostic.show_line_diagnostics()* Use |vim.diagnostic.open_float()| instead. *vim.lsp.diagnostic.show_line_diagnostics()* Use |vim.diagnostic.open_float()| instead.
- *vim.lsp.diagnostic.show_position_diagnostics()* Use |vim.diagnostic.open_float()| instead. *vim.lsp.diagnostic.show_position_diagnostics()* Use |vim.diagnostic.open_float()| instead.
The following are deprecated without replacement. These functions are moved The following are deprecated without replacement. These functions are moved
internally and are no longer exposed as part of the API. Instead, use internally and are no longer exposed as part of the API. Instead, use
|vim.diagnostic.config()| and |vim.diagnostic.show()|. |vim.diagnostic.config()| and |vim.diagnostic.show()|.
- *vim.lsp.diagnostic.set_signs()* *vim.lsp.diagnostic.set_signs()*
- *vim.lsp.diagnostic.set_underline()* *vim.lsp.diagnostic.set_underline()*
- *vim.lsp.diagnostic.set_virtual_text()* *vim.lsp.diagnostic.set_virtual_text()*
LSP FUNCTIONS LSP FUNCTIONS
- *vim.lsp.buf.server_ready()* *vim.lsp.buf.server_ready()*
Use |LspAttach| instead, depending on your use-case. "Server ready" is not Use |LspAttach| instead, depending on your use-case. "Server ready" is not
part of the LSP spec, so the Nvim LSP client cannot meaningfully implement part of the LSP spec, so the Nvim LSP client cannot meaningfully implement
it. "Ready" is ambiguous because: it. "Ready" is ambiguous because:
- Language servers may finish analyzing the workspace, but edits can always Language servers may finish analyzing the workspace, but edits can always
re-trigger analysis/builds. re-trigger analysis/builds.
- Language servers can serve some requests even while processing changes. Language servers can serve some requests even while processing changes.
- *vim.lsp.buf.range_code_action()* Use |vim.lsp.buf.code_action()| with *vim.lsp.buf.range_code_action()* Use |vim.lsp.buf.code_action()| with
the `range` parameter. the `range` parameter.
- *vim.lsp.util.diagnostics_to_items()* Use |vim.diagnostic.toqflist()| instead. *vim.lsp.util.diagnostics_to_items()* Use |vim.diagnostic.toqflist()| instead.
- *vim.lsp.util.set_qflist()* Use |setqflist()| instead. *vim.lsp.util.set_qflist()* Use |setqflist()| instead.
- *vim.lsp.util.set_loclist()* Use |setloclist()| instead. *vim.lsp.util.set_loclist()* Use |setloclist()| instead.
- *vim.lsp.buf_get_clients()* Use |vim.lsp.get_clients()| with *vim.lsp.buf_get_clients()* Use |vim.lsp.get_clients()| with
{buffer=bufnr} instead. {buffer=bufnr} instead.
- *vim.lsp.buf.formatting()* Use |vim.lsp.buf.format()| with *vim.lsp.buf.formatting()* Use |vim.lsp.buf.format()| with
{async=true} instead. {async=true} instead.
- *vim.lsp.buf.formatting_sync()* Use |vim.lsp.buf.format()| with *vim.lsp.buf.formatting_sync()* Use |vim.lsp.buf.format()| with
{async=false} instead. {async=false} instead.
- *vim.lsp.buf.range_formatting()* Use |vim.lsp.formatexpr()| *vim.lsp.buf.range_formatting()* Use |vim.lsp.formatexpr()|
or |vim.lsp.buf.format()| instead. or |vim.lsp.buf.format()| instead.
LUA LUA
- vim.register_keystroke_callback() Use |vim.on_key()| instead. vim.register_keystroke_callback() Use |vim.on_key()| instead.
NORMAL COMMANDS NORMAL COMMANDS
- *]f* *[f* Same as "gf". *]f* *[f* Same as "gf".
OPTIONS OPTIONS
- *cpo-<* *:menu-<special>* *:menu-special* *:map-<special>* *:map-special* *cpo-<* *:menu-<special>* *:menu-special* *:map-<special>* *:map-special*
`<>` notation is always enabled. `<>` notation is always enabled.
- *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used. *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
- *'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed. *'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed.
- *'langnoremap'* Deprecated alias to 'nolangremap'. *'langnoremap'* Deprecated alias to 'nolangremap'.
- 'sessionoptions' Flags "unix", "slash" are ignored and always enabled. 'sessionoptions' Flags "unix", "slash" are ignored and always enabled.
- *'vi'* *'vi'*
- 'viewoptions' Flags "unix", "slash" are ignored and always enabled. 'viewoptions' Flags "unix", "slash" are ignored and always enabled.
- *'viminfo'* Deprecated alias to 'shada' option. *'viminfo'* Deprecated alias to 'shada' option.
- *'viminfofile'* Deprecated alias to 'shadafile' option. *'viminfofile'* Deprecated alias to 'shadafile' option.
- *'paste'* *'nopaste'* Just Paste It.™ The 'paste' option is obsolete: *'paste'* *'nopaste'* Just Paste It.™ The 'paste' option is obsolete:
|paste| is handled automatically when you paste text |paste| is handled automatically when you paste text
using your terminal's or GUI's paste feature using your terminal's or GUI's paste feature
(CTRL-SHIFT-v, CMD-v (macOS), middle-click, …). (CTRL-SHIFT-v, CMD-v (macOS), middle-click, …).
Enables "paste mode": Enables "paste mode":
- Disables mappings in Insert, Cmdline mode. Disables mappings in Insert, Cmdline mode.
- Disables abbreviations. Disables abbreviations.
- Resets 'autoindent' 'expandtab' 'revins' 'ruler' Resets 'autoindent' 'expandtab' 'revins' 'ruler'
'showmatch' 'smartindent' 'smarttab' 'softtabstop' 'showmatch' 'smartindent' 'smarttab' 'softtabstop'
'textwidth' 'wrapmargin'. 'textwidth' 'wrapmargin'.
- Treats 'formatoptions' as empty. Treats 'formatoptions' as empty.
- Disables the effect of these options: Disables the effect of these options:
- 'cindent' 'cindent'
- 'indentexpr' 'indentexpr'
- 'lisp' 'lisp'
UI EXTENSIONS UI EXTENSIONS
- *ui-wildmenu* Use |ui-cmdline| with |ui-popupmenu| instead. Enabled *ui-wildmenu* Use |ui-cmdline| with |ui-popupmenu| instead. Enabled
by the `ext_wildmenu` |ui-option|. Emits these events: by the `ext_wildmenu` |ui-option|. Emits these events:
- `["wildmenu_show", items]` `["wildmenu_show", items]`
- `["wildmenu_select", selected]` `["wildmenu_select", selected]`
- `["wildmenu_hide"]` `["wildmenu_hide"]`
- *term_background* Unused. The terminal background color is now detected *term_background* Unused. The terminal background color is now detected
by the Nvim core directly instead of the TUI. by the Nvim core directly instead of the TUI.
VARIABLES VARIABLES
- *b:terminal_job_pid* Use `jobpid(&channel)` instead. • *b:terminal_job_pid* Use `jobpid(&channel)` instead.
- *b:terminal_job_id* Use `&channel` instead. To access in non-current buffer: • *b:terminal_job_id* Use `&channel` instead. To access in non-current buffer:
- Lua: `vim.bo[bufnr].channel` • Lua: `vim.bo[bufnr].channel`
- Vimscript: `getbufvar(bufnr, '&channel')` • Vimscript: `getbufvar(bufnr, '&channel')`
VIMSCRIPT
• *buffer_exists()* Obsolete name for |bufexists()|.
• *buffer_name()* Obsolete name for |bufname()|.
• *buffer_number()* Obsolete name for |bufnr()|.
• *file_readable()* Obsolete name for |filereadable()|.
• *highlight_exists()* Obsolete name for |hlexists()|.
• *highlightID()* Obsolete name for |hlID()|.
• *inputdialog()* Use |input()| instead.
• *jobclose()* Obsolete name for |chanclose()|
• *jobsend()* Obsolete name for |chansend()|
• *last_buffer_nr()* Obsolete name for bufnr("$").
• *rpcstart()* Use |jobstart()| with `{'rpc': v:true}` instead.
• *rpcstop()* Use |jobstop()| instead to stop any job, or
`chanclose(id, "rpc")` to close RPC communication
without stopping the job. Use chanclose(id) to close
any socket.
vim:noet:tw=78:ts=8:ft=help:norl: vim:noet:tw=78:ts=8:ft=help:norl:

View File

@ -294,6 +294,7 @@ TERMINAL
means that the |TermCursorNC| highlight group is no longer supported: an means that the |TermCursorNC| highlight group is no longer supported: an
unfocused terminal window will have no cursor at all (so there is nothing to unfocused terminal window will have no cursor at all (so there is nothing to
highlight). highlight).
• |jobstart()| gained the "term" flag.
TREESITTER TREESITTER

View File

@ -26,7 +26,7 @@ Start *terminal-start*
There are several ways to create a terminal buffer: There are several ways to create a terminal buffer:
- Run the |:terminal| command. - Run the |:terminal| command.
- Call the |nvim_open_term()| or |termopen()| function. - Call |nvim_open_term()| or `jobstart(…, {'term': v:true})`.
- Edit a "term://" buffer. Examples: >vim - Edit a "term://" buffer. Examples: >vim
:edit term://bash :edit term://bash
:vsplit term://top :vsplit term://top

View File

@ -435,7 +435,7 @@ do
group = nvim_terminal_augroup, group = nvim_terminal_augroup,
desc = 'Treat term:// buffers as terminal buffers', desc = 'Treat term:// buffers as terminal buffers',
nested = true, nested = true,
command = "if !exists('b:term_title')|call termopen(matchstr(expand(\"<amatch>\"), '\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), {'cwd': expand(get(matchlist(expand(\"<amatch>\"), '\\c\\mterm://\\(.\\{-}\\)//'), 1, ''))})", command = "if !exists('b:term_title')|call jobstart(matchstr(expand(\"<amatch>\"), '\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), {'term': v:true, 'cwd': expand(get(matchlist(expand(\"<amatch>\"), '\\c\\mterm://\\(.\\{-}\\)//'), 1, ''))})",
}) })
vim.api.nvim_create_autocmd({ 'TermClose' }, { vim.api.nvim_create_autocmd({ 'TermClose' }, {

View File

@ -272,12 +272,12 @@ function vim.api.nvim_buf_attach(buffer, send_buffer, opts) end
--- This temporarily switches current buffer to "buffer". --- This temporarily switches current buffer to "buffer".
--- If the current window already shows "buffer", the window is not switched. --- If the current window already shows "buffer", the window is not switched.
--- If a window inside the current tabpage (including a float) already shows the --- If a window inside the current tabpage (including a float) already shows the
--- buffer, then one of these windows will be set as current window temporarily. --- buffer, then one of those windows will be set as current window temporarily.
--- Otherwise a temporary scratch window (called the "autocmd window" for --- Otherwise a temporary scratch window (called the "autocmd window" for
--- historical reasons) will be used. --- historical reasons) will be used.
--- ---
--- This is useful e.g. to call Vimscript functions that only work with the --- This is useful e.g. to call Vimscript functions that only work with the
--- current buffer/window currently, like `termopen()`. --- current buffer/window currently, like `jobstart(…, {'term': v:true})`.
--- ---
--- @param buffer integer Buffer handle, or 0 for current buffer --- @param buffer integer Buffer handle, or 0 for current buffer
--- @param fun function Function to call inside the buffer (currently Lua callable --- @param fun function Function to call inside the buffer (currently Lua callable

View File

@ -4805,7 +4805,7 @@ function vim.fn.jobresize(job, width, height) end
--- @return any --- @return any
function vim.fn.jobsend(...) end function vim.fn.jobsend(...) end
--- Note: Prefer |vim.system()| in Lua (unless using the `pty` option). --- Note: Prefer |vim.system()| in Lua (unless using `rpc`, `pty`, or `term`).
--- ---
--- Spawns {cmd} as a job. --- Spawns {cmd} as a job.
--- If {cmd} is a List it runs directly (no 'shell'). --- If {cmd} is a List it runs directly (no 'shell').
@ -4879,6 +4879,10 @@ function vim.fn.jobsend(...) end
--- stdin: (string) Either "pipe" (default) to connect the --- stdin: (string) Either "pipe" (default) to connect the
--- job's stdin to a channel or "null" to disconnect --- job's stdin to a channel or "null" to disconnect
--- stdin. --- stdin.
--- term: (boolean) Spawns {cmd} in a new pseudo-terminal session
--- connected to the current (unmodified) buffer. Implies "pty".
--- Default "height" and "width" are set to the current window
--- dimensions. |jobstart()|. Defaults $TERM to "xterm-256color".
--- width: (number) Width of the `pty` terminal. --- width: (number) Width of the `pty` terminal.
--- ---
--- {opts} is passed as |self| dictionary to the callback; the --- {opts} is passed as |self| dictionary to the callback; the
@ -10168,19 +10172,8 @@ function vim.fn.tanh(expr) end
--- @return string --- @return string
function vim.fn.tempname() end function vim.fn.tempname() end
--- Spawns {cmd} in a new pseudo-terminal session connected --- @deprecated
--- to the current (unmodified) buffer. Parameters and behavior --- Use |jobstart()| with `{term: v:true}` instead.
--- are the same as |jobstart()| except "pty", "width", "height",
--- and "TERM" are ignored: "height" and "width" are taken from
--- the current window. Note that termopen() implies a "pty" arg
--- to jobstart(), and thus has the implications documented at
--- |jobstart()|.
---
--- Returns the same values as jobstart().
---
--- Terminal environment is initialized as in |jobstart-env|,
--- except $TERM is set to "xterm-256color". Full behavior is
--- described in |terminal|.
--- ---
--- @param cmd string|string[] --- @param cmd string|string[]
--- @param opts? table --- @param opts? table

View File

@ -38,7 +38,7 @@
" NEOVIM COMPATIBILITY " NEOVIM COMPATIBILITY
" "
" The vim specific functionalities were replaced with neovim specific calls: " The vim specific functionalities were replaced with neovim specific calls:
" - term_start -> termopen " - term_start -> `jobstart(…, {'term': v:true})`
" - term_sendkeys -> chansend " - term_sendkeys -> chansend
" - term_getline -> getbufline " - term_getline -> getbufline
" - job_info && term_getjob -> nvim_get_chan_info " - job_info && term_getjob -> nvim_get_chan_info
@ -251,7 +251,7 @@ endfunc
" Open a terminal window without a job, to run the debugged program in. " Open a terminal window without a job, to run the debugged program in.
func s:StartDebug_term(dict) func s:StartDebug_term(dict)
execute s:vertical ? 'vnew' : 'new' execute s:vertical ? 'vnew' : 'new'
let s:pty_job_id = termopen('tail -f /dev/null;#gdb program') let s:pty_job_id = jobstart('tail -f /dev/null;#gdb program', {'term': v:true})
if s:pty_job_id == 0 if s:pty_job_id == 0
call s:Echoerr('Invalid argument (or job table is full) while opening terminal window') call s:Echoerr('Invalid argument (or job table is full) while opening terminal window')
return return
@ -323,7 +323,7 @@ func s:StartDebug_term(dict)
execute 'new' execute 'new'
" call ch_log($'executing "{join(gdb_cmd)}"') " call ch_log($'executing "{join(gdb_cmd)}"')
let s:gdb_job_id = termopen(gdb_cmd, {'on_exit': function('s:EndTermDebug')}) let s:gdb_job_id = jobstart(gdb_cmd, {'term': v:true, 'on_exit': function('s:EndTermDebug')})
if s:gdb_job_id == 0 if s:gdb_job_id == 0
call s:Echoerr('Invalid argument (or job table is full) while opening gdb terminal window') call s:Echoerr('Invalid argument (or job table is full) while opening gdb terminal window')
exe 'bwipe! ' . s:ptybufnr exe 'bwipe! ' . s:ptybufnr
@ -491,7 +491,7 @@ func s:StartDebug_prompt(dict)
" Unix: Run the debugged program in a terminal window. Open it below the " Unix: Run the debugged program in a terminal window. Open it below the
" gdb window. " gdb window.
belowright new belowright new
let s:pty_job_id = termopen('tail -f /dev/null;#gdb program') let s:pty_job_id = jobstart('tail -f /dev/null;#gdb program', {'term': v:true})
if s:pty_job_id == 0 if s:pty_job_id == 0
call s:Echoerr('Invalid argument (or job table is full) while opening terminal window') call s:Echoerr('Invalid argument (or job table is full) while opening terminal window')
return return

View File

@ -1181,12 +1181,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena,
/// This temporarily switches current buffer to "buffer". /// This temporarily switches current buffer to "buffer".
/// If the current window already shows "buffer", the window is not switched. /// If the current window already shows "buffer", the window is not switched.
/// If a window inside the current tabpage (including a float) already shows the /// If a window inside the current tabpage (including a float) already shows the
/// buffer, then one of these windows will be set as current window temporarily. /// buffer, then one of those windows will be set as current window temporarily.
/// Otherwise a temporary scratch window (called the "autocmd window" for /// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used. /// historical reasons) will be used.
/// ///
/// This is useful e.g. to call Vimscript functions that only work with the /// This is useful e.g. to call Vimscript functions that only work with the
/// current buffer/window currently, like |termopen()|. /// current buffer/window currently, like `jobstart(…, {'term': v:true})`.
/// ///
/// @param buffer Buffer handle, or 0 for current buffer /// @param buffer Buffer handle, or 0 for current buffer
/// @param fun Function to call inside the buffer (currently Lua callable /// @param fun Function to call inside the buffer (currently Lua callable

View File

@ -8493,7 +8493,7 @@ char *do_string_sub(char *str, size_t len, char *pat, char *sub, typval_T *expr,
return ret; return ret;
} }
/// common code for getting job callbacks for jobstart, termopen and rpcstart /// Common code for getting job callbacks for `jobstart`.
/// ///
/// @return true/false on success/failure. /// @return true/false on success/failure.
bool common_job_callbacks(dict_T *vopts, CallbackReader *on_stdout, CallbackReader *on_stderr, bool common_job_callbacks(dict_T *vopts, CallbackReader *on_stdout, CallbackReader *on_stderr,

View File

@ -5945,7 +5945,7 @@ M.funcs = {
jobstart = { jobstart = {
args = { 1, 2 }, args = { 1, 2 },
desc = [=[ desc = [=[
Note: Prefer |vim.system()| in Lua (unless using the `pty` option). Note: Prefer |vim.system()| in Lua (unless using `rpc`, `pty`, or `term`).
Spawns {cmd} as a job. Spawns {cmd} as a job.
If {cmd} is a List it runs directly (no 'shell'). If {cmd} is a List it runs directly (no 'shell').
@ -6019,6 +6019,10 @@ M.funcs = {
stdin: (string) Either "pipe" (default) to connect the stdin: (string) Either "pipe" (default) to connect the
job's stdin to a channel or "null" to disconnect job's stdin to a channel or "null" to disconnect
stdin. stdin.
term: (boolean) Spawns {cmd} in a new pseudo-terminal session
connected to the current (unmodified) buffer. Implies "pty".
Default "height" and "width" are set to the current window
dimensions. |jobstart()|. Defaults $TERM to "xterm-256color".
width: (number) Width of the `pty` terminal. width: (number) Width of the `pty` terminal.
{opts} is passed as |self| dictionary to the callback; the {opts} is passed as |self| dictionary to the callback; the
@ -12271,21 +12275,10 @@ M.funcs = {
signature = 'tempname()', signature = 'tempname()',
}, },
termopen = { termopen = {
deprecated = true,
args = { 1, 2 }, args = { 1, 2 },
desc = [=[ desc = [=[
Spawns {cmd} in a new pseudo-terminal session connected Use |jobstart()| with `{term: v:true}` instead.
to the current (unmodified) buffer. Parameters and behavior
are the same as |jobstart()| except "pty", "width", "height",
and "TERM" are ignored: "height" and "width" are taken from
the current window. Note that termopen() implies a "pty" arg
to jobstart(), and thus has the implications documented at
|jobstart()|.
Returns the same values as jobstart().
Terminal environment is initialized as in |jobstart-env|,
except $TERM is set to "xterm-256color". Full behavior is
described in |terminal|.
]=], ]=],
name = 'termopen', name = 'termopen',
params = { { 'cmd', 'string|string[]' }, { 'opts', 'table' } }, params = { { 'cmd', 'string|string[]' }, { 'opts', 'table' } },

View File

@ -0,0 +1,44 @@
#include <stdbool.h> // for true
#include "nvim/errors.h"
#include "nvim/eval/deprecated.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
#include "nvim/gettext_defs.h" // for _
#include "nvim/macros_defs.h" // for S_LEN
#include "nvim/message.h" // for semsg
#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/deprecated.c.generated.h"
#endif
/// "termopen(cmd[, cwd])" function
void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
}
bool must_free = false;
if (argvars[1].v_type == VAR_UNKNOWN) {
must_free = true;
argvars[1].v_type = VAR_DICT;
argvars[1].vval.v_dict = tv_dict_alloc();
}
if (argvars[1].v_type != VAR_DICT) {
// Wrong argument types
semsg(_(e_invarg2), "expected dictionary");
return;
}
tv_dict_add_bool(argvars[1].vval.v_dict, S_LEN("term"), true);
f_jobstart(argvars, rettv, fptr);
if (must_free) {
tv_dict_free(argvars[1].vval.v_dict);
}
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <stdbool.h> // for true
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/deprecated.h.generated.h"
#endif

View File

@ -38,6 +38,7 @@
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/buffer.h" #include "nvim/eval/buffer.h"
#include "nvim/eval/decode.h" #include "nvim/eval/decode.h"
#include "nvim/eval/deprecated.h"
#include "nvim/eval/encode.h" #include "nvim/eval/encode.h"
#include "nvim/eval/executor.h" #include "nvim/eval/executor.h"
#include "nvim/eval/funcs.h" #include "nvim/eval/funcs.h"
@ -3840,8 +3841,8 @@ static const char *required_env_vars[] = {
NULL NULL
}; };
static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, const bool pty, dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, const bool pty,
const char * const pty_term_name) const char * const pty_term_name)
{ {
dict_T *env = tv_dict_alloc(); dict_T *env = tv_dict_alloc();
@ -3933,7 +3934,7 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
} }
/// "jobstart()" function /// "jobstart()" function
static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
rettv->v_type = VAR_NUMBER; rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0; rettv->vval.v_number = 0;
@ -3942,9 +3943,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
return; return;
} }
const char *cmd;
bool executable = true; bool executable = true;
char **argv = tv_to_argv(&argvars[0], NULL, &executable); char **argv = tv_to_argv(&argvars[0], &cmd, &executable);
dict_T *env = NULL;
if (!argv) { if (!argv) {
rettv->vval.v_number = executable ? 0 : -1; rettv->vval.v_number = executable ? 0 : -1;
return; // Did error message in tv_to_argv. return; // Did error message in tv_to_argv.
@ -3961,6 +3962,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool detach = false; bool detach = false;
bool rpc = false; bool rpc = false;
bool pty = false; bool pty = false;
bool term = false;
bool clear_env = false; bool clear_env = false;
bool overlapped = false; bool overlapped = false;
ChannelStdinMode stdin_mode = kChannelStdinPipe; ChannelStdinMode stdin_mode = kChannelStdinPipe;
@ -3974,7 +3976,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
detach = tv_dict_get_number(job_opts, "detach") != 0; detach = tv_dict_get_number(job_opts, "detach") != 0;
rpc = tv_dict_get_number(job_opts, "rpc") != 0; rpc = tv_dict_get_number(job_opts, "rpc") != 0;
pty = tv_dict_get_number(job_opts, "pty") != 0; term = tv_dict_get_number(job_opts, "term") != 0;
pty = term || tv_dict_get_number(job_opts, "pty") != 0;
clear_env = tv_dict_get_number(job_opts, "clear_env") != 0; clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
overlapped = tv_dict_get_number(job_opts, "overlapped") != 0; overlapped = tv_dict_get_number(job_opts, "overlapped") != 0;
@ -3989,6 +3992,14 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
} }
} }
dictitem_T *const job_term = tv_dict_find(job_opts, S_LEN("term"));
if (job_term && VAR_BOOL != job_term->di_tv.v_type) {
// Restrict "term" field to boolean, in case we want to allow buffer numbers in the future.
semsg(_(e_invarg2), "'term' must be Boolean");
shell_free_argv(argv);
return;
}
if (pty && rpc) { if (pty && rpc) {
semsg(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set"); semsg(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set");
shell_free_argv(argv); shell_free_argv(argv);
@ -4032,23 +4043,83 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
uint16_t height = 0; uint16_t height = 0;
char *term_name = NULL; char *term_name = NULL;
if (pty) { if (term) {
width = (uint16_t)tv_dict_get_number(job_opts, "width"); if (text_locked()) {
height = (uint16_t)tv_dict_get_number(job_opts, "height"); text_locked_msg();
// Legacy method, before env option existed, to specify $TERM. No longer shell_free_argv(argv);
// documented, but still usable to avoid breaking scripts. return;
term_name = tv_dict_get_string(job_opts, "TERM", false);
if (!term_name) {
term_name = "ansi";
} }
if (curbuf->b_changed) {
emsg(_("jobstart(...,{term:true}) requires unmodified buffer"));
return;
}
assert(!rpc);
term_name = "xterm-256color";
cwd = cwd ? cwd : ".";
overlapped = false;
detach = false;
stdin_mode = kChannelStdinPipe;
width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin));
height = (uint16_t)curwin->w_height_inner;
} }
env = create_environment(job_env, clear_env, pty, term_name); if (pty) {
width = width ? width : (uint16_t)tv_dict_get_number(job_opts, "width");
height = height ? height : (uint16_t)tv_dict_get_number(job_opts, "height");
// Deprecated TERM field is from before `env` option existed.
term_name = term_name ? term_name : tv_dict_get_string(job_opts, "TERM", false);
term_name = term_name ? term_name : "ansi";
}
dict_T *env = create_environment(job_env, clear_env, pty, term_name);
Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit, pty, Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit, pty,
rpc, overlapped, detach, stdin_mode, cwd, rpc, overlapped, detach, stdin_mode, cwd,
width, height, env, &rettv->vval.v_number); width, height, env, &rettv->vval.v_number);
if (chan) { if (term) {
if (rettv->vval.v_number <= 0) {
return;
}
int pid = chan->stream.pty.proc.pid;
// "./…" => "/home/foo/…"
vim_FullName(cwd, NameBuff, sizeof(NameBuff), false);
// "/home/foo/…" => "~/…"
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = NUL;
}
if (len == 1 && IObuff[0] == '/') {
// Avoid ambiguity in the URI when CWD is root directory.
IObuff[1] = '.';
IObuff[2] = NUL;
}
// Terminal URI: "term://$CWD//$PID:$CMD"
snprintf(NameBuff, sizeof(NameBuff), "term://%s//%d:%s", IObuff, pid, cmd);
// Buffer has no terminal associated yet; unset 'swapfile' to ensure no swapfile is created.
curbuf->b_p_swf = false;
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
setfname(curbuf, NameBuff, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
Error err = ERROR_INIT;
// Set (deprecated) buffer-local vars (prefer 'channel' buffer-local option).
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
INTEGER_OBJ((Integer)chan->id), false, false, NULL, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
INTEGER_OBJ(pid), false, false, NULL, &err);
api_clear_error(&err);
channel_incref(chan);
channel_terminal_open(curbuf, chan);
channel_create_event(chan, NULL);
channel_decref(chan);
} else if (chan) {
channel_create_event(chan, NULL); channel_create_event(chan, NULL);
} }
} }
@ -8133,134 +8204,6 @@ static void f_taglist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
(char *)tag_pattern, (char *)fname); (char *)tag_pattern, (char *)fname);
} }
/// "termopen(cmd[, cwd])" function
static void f_termopen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
if (check_secure()) {
return;
}
if (text_locked()) {
text_locked_msg();
return;
}
if (curbuf->b_changed) {
emsg(_("Can only call this function in an unmodified buffer"));
return;
}
const char *cmd;
bool executable = true;
char **argv = tv_to_argv(&argvars[0], &cmd, &executable);
if (!argv) {
rettv->vval.v_number = executable ? 0 : -1;
return; // Did error message in tv_to_argv.
}
if (argvars[1].v_type != VAR_DICT && argvars[1].v_type != VAR_UNKNOWN) {
// Wrong argument type
semsg(_(e_invarg2), "expected dictionary");
shell_free_argv(argv);
return;
}
CallbackReader on_stdout = CALLBACK_READER_INIT;
CallbackReader on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
dict_T *job_opts = NULL;
const char *cwd = ".";
dict_T *env = NULL;
const bool pty = true;
bool clear_env = false;
dictitem_T *job_env = NULL;
if (argvars[1].v_type == VAR_DICT) {
job_opts = argvars[1].vval.v_dict;
const char *const new_cwd = tv_dict_get_string(job_opts, "cwd", false);
if (new_cwd && *new_cwd != NUL) {
cwd = new_cwd;
// The new cwd must be a directory.
if (!os_isdir(cwd)) {
semsg(_(e_invarg2), "expected valid directory");
shell_free_argv(argv);
return;
}
}
job_env = tv_dict_find(job_opts, S_LEN("env"));
if (job_env && job_env->di_tv.v_type != VAR_DICT) {
semsg(_(e_invarg2), "env");
shell_free_argv(argv);
return;
}
clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
if (!common_job_callbacks(job_opts, &on_stdout, &on_stderr, &on_exit)) {
shell_free_argv(argv);
return;
}
}
env = create_environment(job_env, clear_env, pty, "xterm-256color");
const bool rpc = false;
const bool overlapped = false;
const bool detach = false;
ChannelStdinMode stdin_mode = kChannelStdinPipe;
uint16_t term_width = (uint16_t)MAX(0, curwin->w_width_inner - win_col_off(curwin));
Channel *chan = channel_job_start(argv, NULL, on_stdout, on_stderr, on_exit,
pty, rpc, overlapped, detach, stdin_mode,
cwd, term_width, (uint16_t)curwin->w_height_inner,
env, &rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
return;
}
int pid = chan->stream.pty.proc.pid;
// "./…" => "/home/foo/…"
vim_FullName(cwd, NameBuff, sizeof(NameBuff), false);
// "/home/foo/…" => "~/…"
size_t len = home_replace(NULL, NameBuff, IObuff, sizeof(IObuff), true);
// Trim slash.
if (len != 1 && (IObuff[len - 1] == '\\' || IObuff[len - 1] == '/')) {
IObuff[len - 1] = NUL;
}
if (len == 1 && IObuff[0] == '/') {
// Avoid ambiguity in the URI when CWD is root directory.
IObuff[1] = '.';
IObuff[2] = NUL;
}
// Terminal URI: "term://$CWD//$PID:$CMD"
snprintf(NameBuff, sizeof(NameBuff), "term://%s//%d:%s",
IObuff, pid, cmd);
// at this point the buffer has no terminal instance associated yet, so unset
// the 'swapfile' option to ensure no swap file will be created
curbuf->b_p_swf = false;
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
setfname(curbuf, NameBuff, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
// Save the job id and pid in b:terminal_job_{id,pid}
Error err = ERROR_INIT;
// deprecated: use 'channel' buffer option
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_id"),
INTEGER_OBJ((Integer)chan->id), false, false, NULL, &err);
api_clear_error(&err);
dict_set_var(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
INTEGER_OBJ(pid), false, false, NULL, &err);
api_clear_error(&err);
channel_incref(chan);
channel_terminal_open(curbuf, chan);
channel_create_event(chan, NULL);
channel_decref(chan);
}
/// "timer_info([timer])" function /// "timer_info([timer])" function
static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void f_timer_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {

View File

@ -7775,7 +7775,7 @@ static void ex_terminal(exarg_T *eap)
if (*eap->arg != NUL) { // Run {cmd} in 'shell'. if (*eap->arg != NUL) { // Run {cmd} in 'shell'.
char *name = vim_strsave_escaped(eap->arg, "\"\\"); char *name = vim_strsave_escaped(eap->arg, "\"\\");
snprintf(ex_cmd + len, sizeof(ex_cmd) - len, snprintf(ex_cmd + len, sizeof(ex_cmd) - len,
" | call termopen(\"%s\")", name); " | call jobstart(\"%s\",{'term':v:true})", name);
xfree(name); xfree(name);
} else { // No {cmd}: run the job with tokenized 'shell'. } else { // No {cmd}: run the job with tokenized 'shell'.
if (*p_sh == NUL) { if (*p_sh == NUL) {
@ -7798,7 +7798,7 @@ static void ex_terminal(exarg_T *eap)
shell_free_argv(argv); shell_free_argv(argv);
snprintf(ex_cmd + len, sizeof(ex_cmd) - len, snprintf(ex_cmd + len, sizeof(ex_cmd) - len,
" | call termopen([%s])", shell_argv + 1); " | call jobstart([%s], {'term':v:true})", shell_argv + 1);
} }
do_cmdline_cmd(ex_cmd); do_cmdline_cmd(ex_cmd);

View File

@ -19,6 +19,7 @@ hashpipe:write([[
#include "nvim/digraph.h" #include "nvim/digraph.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/buffer.h" #include "nvim/eval/buffer.h"
#include "nvim/eval/deprecated.h"
#include "nvim/eval/fs.h" #include "nvim/eval/fs.h"
#include "nvim/eval/funcs.h" #include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"

View File

@ -357,7 +357,7 @@ static void term_output_callback(const char *s, size_t len, void *user_data)
/// Initializes terminal properties, and triggers TermOpen. /// Initializes terminal properties, and triggers TermOpen.
/// ///
/// The PTY process (TerminalOptions.data) was already started by termopen(), /// The PTY process (TerminalOptions.data) was already started by jobstart(),
/// via ex_terminal() or the term:// BufReadCmd. /// via ex_terminal() or the term:// BufReadCmd.
/// ///
/// @param buf Buffer used for presentation of the terminal. /// @param buf Buffer used for presentation of the terminal.

View File

@ -879,7 +879,8 @@ describe('API: buffer events:', function()
it('when :terminal lines change', function() it('when :terminal lines change', function()
local buffer_lines = {} local buffer_lines = {}
local expected_lines = {} local expected_lines = {}
fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '-n', '-c', 'set shortmess+=A' }, { fn.jobstart({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '-n', '-c', 'set shortmess+=A' }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })

View File

@ -2704,7 +2704,8 @@ describe('API', function()
-- :terminal with args + running process. -- :terminal with args + running process.
command('enew') command('enew')
local progpath_esc = eval('shellescape(v:progpath)') local progpath_esc = eval('shellescape(v:progpath)')
fn.termopen(('%s -u NONE -i NONE'):format(progpath_esc), { fn.jobstart(('%s -u NONE -i NONE'):format(progpath_esc), {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running? eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running?

View File

@ -65,6 +65,31 @@ describe('jobs', function()
]]) ]])
end) end)
it('validation', function()
matches(
"E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set",
pcall_err(command, "let j = jobstart(['cat', '-'], { 'pty': v:true, 'rpc': v:true })")
)
matches(
'E475: Invalid argument: expected valid directory',
pcall_err(command, "let j = jobstart(['cat', '-'], { 'cwd': 1 })")
)
matches(
'E475: Invalid argument: expected valid directory',
pcall_err(command, "let j = jobstart(['cat', '-'], { 'cwd': 'bogusssssss/bogus' })")
)
matches(
"E475: Invalid argument: 'term' must be Boolean",
pcall_err(command, "let j = jobstart(['cat', '-'], { 'term': 'bogus' })")
)
matches(
"E475: Invalid argument: 'term' must be Boolean",
pcall_err(command, "let j = jobstart(['cat', '-'], { 'term': 1 })")
)
command("let j = jobstart(['cat', '-'], { 'term': v:true })")
command("let j = jobstart(['cat', '-'], { 'term': v:false })")
end)
it('must specify env option as a dict', function() it('must specify env option as a dict', function()
command('let g:job_opts.env = v:true') command('let g:job_opts.env = v:true')
local _, err = pcall(function() local _, err = pcall(function()
@ -969,13 +994,6 @@ describe('jobs', function()
eq({ 'notification', 'exit', { 0, 143 } }, next_msg()) eq({ 'notification', 'exit', { 0, 143 } }, next_msg())
end) end)
it('cannot have both rpc and pty options', function()
command('let g:job_opts.pty = v:true')
command('let g:job_opts.rpc = v:true')
local _, err = pcall(command, "let j = jobstart(['cat', '-'], g:job_opts)")
matches("E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set", err)
end)
it('does not crash when repeatedly failing to start shell', function() it('does not crash when repeatedly failing to start shell', function()
source([[ source([[
set shell=nosuchshell set shell=nosuchshell
@ -1230,7 +1248,7 @@ describe('pty process teardown', function()
it('does not prevent/delay exit. #4798 #4900', function() it('does not prevent/delay exit. #4798 #4900', function()
skip(fn.executable('sleep') == 0, 'missing "sleep" command') skip(fn.executable('sleep') == 0, 'missing "sleep" command')
-- Use a nested nvim (in :term) to test without --headless. -- Use a nested nvim (in :term) to test without --headless.
fn.termopen({ fn.jobstart({
n.nvim_prog, n.nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -1243,7 +1261,10 @@ describe('pty process teardown', function()
'+terminal', '+terminal',
'+!(sleep 300 &)', '+!(sleep 300 &)',
'+qa', '+qa',
}, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } }) }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
-- Exiting should terminate all descendants (PTY, its children, ...). -- Exiting should terminate all descendants (PTY, its children, ...).
screen:expect([[ screen:expect([[

View File

@ -103,7 +103,8 @@ describe('command-line option', function()
-- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read -- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read
-- data from the terminal #18181 -- data from the terminal #18181
fn.termopen(string.format([[echo "" | %s]], table.concat(args, ' ')), { fn.jobstart(string.format([[echo "" | %s]], table.concat(args, ' ')), {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
screen:expect( screen:expect(

View File

@ -55,7 +55,10 @@ describe('startup', function()
clear() clear()
local screen local screen
screen = Screen.new(84, 3) screen = Screen.new(84, 3)
fn.termopen({ nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' }) fn.jobstart(
{ nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' },
{ term = true }
)
screen:expect([[ screen:expect([[
^Cannot attach UI of :terminal child to its parent. (Unset $NVIM to skip this check) | ^Cannot attach UI of :terminal child to its parent. (Unset $NVIM to skip this check) |
|*2 |*2
@ -98,7 +101,7 @@ describe('startup', function()
screen = Screen.new(60, 7) screen = Screen.new(60, 7)
-- not the same colors on windows for some reason -- not the same colors on windows for some reason
screen._default_attr_ids = nil screen._default_attr_ids = nil
local id = fn.termopen({ local id = fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -108,6 +111,7 @@ describe('startup', function()
'set noruler', 'set noruler',
'-D', '-D',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -360,7 +364,7 @@ describe('startup', function()
command([[set shellcmdflag=/s\ /c shellxquote=\"]]) command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end end
-- Running in :terminal -- Running in :terminal
fn.termopen({ fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -371,6 +375,7 @@ describe('startup', function()
'-c', '-c',
'echo has("ttyin") has("ttyout")', 'echo has("ttyin") has("ttyout")',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -393,13 +398,14 @@ describe('startup', function()
os.remove('Xtest_startup_ttyout') os.remove('Xtest_startup_ttyout')
end) end)
-- Running in :terminal -- Running in :terminal
fn.termopen( fn.jobstart(
( (
[["%s" -u NONE -i NONE --cmd "%s"]] [["%s" -u NONE -i NONE --cmd "%s"]]
.. [[ -c "call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')"]] .. [[ -c "call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')"]]
.. [[ -c q | cat -v]] .. [[ -c q | cat -v]]
):format(nvim_prog, nvim_set), ):format(nvim_prog, nvim_set),
{ {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -424,7 +430,7 @@ describe('startup', function()
os.remove('Xtest_startup_ttyout') os.remove('Xtest_startup_ttyout')
end) end)
-- Running in :terminal -- Running in :terminal
fn.termopen( fn.jobstart(
( (
[[echo foo | ]] -- Input from a pipe. [[echo foo | ]] -- Input from a pipe.
.. [["%s" -u NONE -i NONE --cmd "%s"]] .. [["%s" -u NONE -i NONE --cmd "%s"]]
@ -432,6 +438,7 @@ describe('startup', function()
.. [[ -c q -- -]] .. [[ -c q -- -]]
):format(nvim_prog, nvim_set), ):format(nvim_prog, nvim_set),
{ {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -454,13 +461,14 @@ describe('startup', function()
command([[set shellcmdflag=/s\ /c shellxquote=\"]]) command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end end
-- Running in :terminal -- Running in :terminal
fn.termopen( fn.jobstart(
( (
[[echo foo | ]] [[echo foo | ]]
.. [["%s" -u NONE -i NONE --cmd "%s"]] .. [["%s" -u NONE -i NONE --cmd "%s"]]
.. [[ -c "echo has('ttyin') has('ttyout')"]] .. [[ -c "echo has('ttyin') has('ttyout')"]]
):format(nvim_prog, nvim_set), ):format(nvim_prog, nvim_set),
{ {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -614,7 +622,7 @@ describe('startup', function()
local screen local screen
screen = Screen.new(60, 6) screen = Screen.new(60, 6)
screen._default_attr_ids = nil screen._default_attr_ids = nil
local id = fn.termopen({ local id = fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -625,6 +633,7 @@ describe('startup', function()
'--cmd', '--cmd',
'let g:foo = g:bar', 'let g:foo = g:bar',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -1144,7 +1153,8 @@ describe('user config init', function()
local screen = Screen.new(50, 8) local screen = Screen.new(50, 8)
screen._default_attr_ids = nil screen._default_attr_ids = nil
fn.termopen({ nvim_prog }, { fn.jobstart({ nvim_prog }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -1418,7 +1428,7 @@ describe('inccommand on ex mode', function()
clear() clear()
local screen local screen
screen = Screen.new(60, 10) screen = Screen.new(60, 10)
local id = fn.termopen({ local id = fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -1429,6 +1439,7 @@ describe('inccommand on ex mode', function()
'-E', '-E',
'test/README.md', 'test/README.md',
}, { }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
fn.chansend(id, '%s/N') fn.chansend(id, '%s/N')

View File

@ -26,10 +26,10 @@ describe('Normal mode', function()
it('&showcmd does not crash with :startinsert #28419', function() it('&showcmd does not crash with :startinsert #28419', function()
local screen = Screen.new(60, 17) local screen = Screen.new(60, 17)
fn.termopen( fn.jobstart({ n.nvim_prog, '--clean', '--cmd', 'startinsert' }, {
{ n.nvim_prog, '--clean', '--cmd', 'startinsert' }, term = true,
{ env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } } env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
) })
screen:expect({ screen:expect({
grid = [[ grid = [[
^ | ^ |

View File

@ -115,7 +115,8 @@ describe("preserve and (R)ecover with custom 'directory'", function()
t.skip(t.is_os('win')) t.skip(t.is_os('win'))
local screen0 = Screen.new() local screen0 = Screen.new()
local child_server = new_pipename() local child_server = new_pipename()
fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, { fn.jobstart({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
screen0:expect({ any = pesc('[No Name]') }) -- Wait for the child process to start. screen0:expect({ any = pesc('[No Name]') }) -- Wait for the child process to start.
@ -446,9 +447,10 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end) end)
it('(Q)uit at first file argument', function() it('(Q)uit at first file argument', function()
local chan = fn.termopen( local chan = fn.jobstart(
{ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', init_dir, '--cmd', init_set, testfile }, { nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', init_dir, '--cmd', init_set, testfile },
{ {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
} }
) )
@ -468,7 +470,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end) end)
it('(A)bort at second file argument with -p', function() it('(A)bort at second file argument with -p', function()
local chan = fn.termopen({ local chan = fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -482,6 +484,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
otherfile, otherfile,
testfile, testfile,
}, { }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
retry(nil, nil, function() retry(nil, nil, function()
@ -508,7 +511,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
second %s /^ \zssecond$/ second %s /^ \zssecond$/
third %s /^ \zsthird$/]]):format(testfile, testfile, testfile) third %s /^ \zsthird$/]]):format(testfile, testfile, testfile)
) )
local chan = fn.termopen({ local chan = fn.jobstart({
nvim_prog, nvim_prog,
'-u', '-u',
'NONE', 'NONE',
@ -522,6 +525,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
'set tags=' .. otherfile, 'set tags=' .. otherfile,
'-tsecond', '-tsecond',
}, { }, {
term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}) })
retry(nil, nil, function() retry(nil, nil, function()

View File

@ -120,7 +120,7 @@ describe('splitkeep', function()
row = 0, row = 0,
col = 0, col = 0,
})) }))
vim.cmd("call termopen([&sh, &shcf, 'true'], { 'on_exit': 'C2' })") vim.cmd("call jobstart([&sh, &shcf, 'true'], { 'term': v:true, 'on_exit': 'C2' })")
end end
})]]) })]])
feed('j') feed('j')

View File

@ -378,7 +378,7 @@ describe(':terminal buffer', function()
}, exec_lua('return _G.input')) }, exec_lua('return _G.input'))
end) end)
it('no heap-buffer-overflow when using termopen(echo) #3161', function() it('no heap-buffer-overflow when using jobstart("echo",{term=true}) #3161', function()
local testfilename = 'Xtestfile-functional-terminal-buffers_spec' local testfilename = 'Xtestfile-functional-terminal-buffers_spec'
write_file(testfilename, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa') write_file(testfilename, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa')
finally(function() finally(function()
@ -387,8 +387,8 @@ describe(':terminal buffer', function()
feed_command('edit ' .. testfilename) feed_command('edit ' .. testfilename)
-- Move cursor away from the beginning of the line -- Move cursor away from the beginning of the line
feed('$') feed('$')
-- Let termopen() modify the buffer -- Let jobstart(…,{term=true}) modify the buffer
feed_command('call termopen("echo")') feed_command([[call jobstart("echo", {'term':v:true})]])
assert_alive() assert_alive()
feed_command('bdelete!') feed_command('bdelete!')
end) end)
@ -411,7 +411,7 @@ describe(':terminal buffer', function()
it('handles split UTF-8 sequences #16245', function() it('handles split UTF-8 sequences #16245', function()
local screen = Screen.new(50, 7) local screen = Screen.new(50, 7)
fn.termopen({ testprg('shell-test'), 'UTF-8' }) fn.jobstart({ testprg('shell-test'), 'UTF-8' }, { term = true })
screen:expect([[ screen:expect([[
^å | ^å |
ref: å̲ | ref: å̲ |
@ -669,7 +669,7 @@ if is_os('win') then
end) end)
end end
describe('termopen()', function() describe('termopen() (deprecated alias to `jobstart(…,{term=true})`)', function()
before_each(clear) before_each(clear)
it('disallowed when textlocked and in cmdwin buffer', function() it('disallowed when textlocked and in cmdwin buffer', function()

View File

@ -75,8 +75,8 @@ describe('terminal channel is closed and later released if', function()
eq(chans - 1, eval('len(nvim_list_chans())')) eq(chans - 1, eval('len(nvim_list_chans())'))
end) end)
it('opened by termopen(), exited, and deleted by pressing a key', function() it('opened by jobstart(…,{term=true}), exited, and deleted by pressing a key', function()
command([[let id = termopen('echo')]]) command([[let id = jobstart('echo',{'term':v:true})]])
local chans = eval('len(nvim_list_chans())') local chans = eval('len(nvim_list_chans())')
-- wait for process to exit -- wait for process to exit
screen:expect({ any = '%[Process exited 0%]' }) screen:expect({ any = '%[Process exited 0%]' })
@ -96,8 +96,8 @@ describe('terminal channel is closed and later released if', function()
end) end)
-- This indirectly covers #16264 -- This indirectly covers #16264
it('opened by termopen(), exited, and deleted by :bdelete', function() it('opened by jobstart(…,{term=true}), exited, and deleted by :bdelete', function()
command([[let id = termopen('echo')]]) command([[let id = jobstart('echo', {'term':v:true})]])
local chans = eval('len(nvim_list_chans())') local chans = eval('len(nvim_list_chans())')
-- wait for process to exit -- wait for process to exit
screen:expect({ any = '%[Process exited 0%]' }) screen:expect({ any = '%[Process exited 0%]' })
@ -124,7 +124,7 @@ it('chansend sends lines to terminal channel in proper order', function()
screen._default_attr_ids = nil screen._default_attr_ids = nil
local shells = is_os('win') and { 'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop' } or { 'sh' } local shells = is_os('win') and { 'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop' } or { 'sh' }
for _, sh in ipairs(shells) do for _, sh in ipairs(shells) do
command([[let id = termopen(']] .. sh .. [[')]]) command([[let id = jobstart(']] .. sh .. [[', {'term':v:true})]])
command([[call chansend(id, ['echo "hello"', 'echo "world"', ''])]]) command([[call chansend(id, ['echo "hello"', 'echo "world"', ''])]])
screen:expect { screen:expect {
any = [[echo "hello".*echo "world"]], any = [[echo "hello".*echo "world"]],
@ -149,7 +149,7 @@ describe('no crash when TermOpen autocommand', function()
}) })
end) end)
it('processes job exit event when using termopen()', function() it('processes job exit event when using jobstart(…,{term=true})', function()
command([[autocmd TermOpen * call input('')]]) command([[autocmd TermOpen * call input('')]])
async_meths.nvim_command('terminal foobar') async_meths.nvim_command('terminal foobar')
screen:expect { screen:expect {
@ -179,7 +179,7 @@ describe('no crash when TermOpen autocommand', function()
assert_alive() assert_alive()
end) end)
it('wipes buffer and processes events when using termopen()', function() it('wipes buffer and processes events when using jobstart(…,{term=true})', function()
command([[autocmd TermOpen * bwipe! | call input('')]]) command([[autocmd TermOpen * bwipe! | call input('')]])
async_meths.nvim_command('terminal foobar') async_meths.nvim_command('terminal foobar')
screen:expect { screen:expect {

View File

@ -56,7 +56,7 @@ describe(':terminal', function()
return string.format('\027]52;;%s\027\\', arg) return string.format('\027]52;;%s\027\\', arg)
end end
fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) }) fn.jobstart({ testprg('shell-test'), '-t', osc52(encoded) }, { term = true })
retry(nil, 1000, function() retry(nil, 1000, function()
eq(text, exec_lua([[ return vim.g.clipboard_data ]])) eq(text, exec_lua([[ return vim.g.clipboard_data ]]))

View File

@ -239,7 +239,7 @@ describe(':terminal cursor', function()
feed([[<C-\><C-N>]]) feed([[<C-\><C-N>]])
command('set statusline=~~~') command('set statusline=~~~')
command('new') command('new')
call('termopen', { testprg('tty-test') }) call('jobstart', { testprg('tty-test') }, { term = true })
feed('i') feed('i')
screen:expect({ screen:expect({
grid = [[ grid = [[

View File

@ -175,7 +175,7 @@ local function test_terminal_with_fake_shell(backslash)
api.nvim_set_option_value('shellxquote', '', {}) -- win: avoid extra quotes api.nvim_set_option_value('shellxquote', '', {}) -- win: avoid extra quotes
end) end)
it('with no argument, acts like termopen()', function() it('with no argument, acts like jobstart(…,{term=true})', function()
command('autocmd! nvim_terminal TermClose') command('autocmd! nvim_terminal TermClose')
feed_command('terminal') feed_command('terminal')
screen:expect([[ screen:expect([[
@ -196,7 +196,7 @@ local function test_terminal_with_fake_shell(backslash)
]]) ]])
end) end)
it("with no argument, but 'shell' has arguments, acts like termopen()", function() it("with no argument, but 'shell' has arguments, acts like jobstart(…,{term=true})", function()
api.nvim_set_option_value('shell', shell_path .. ' INTERACT', {}) api.nvim_set_option_value('shell', shell_path .. ' INTERACT', {})
feed_command('terminal') feed_command('terminal')
screen:expect([[ screen:expect([[

View File

@ -33,7 +33,7 @@ describe(':terminal highlight', function()
[12] = { bold = true, underdouble = true }, [12] = { bold = true, underdouble = true },
[13] = { italic = true, undercurl = true }, [13] = { italic = true, undercurl = true },
}) })
command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i') feed('i')
screen:expect([[ screen:expect([[
tty ready | tty ready |
@ -150,7 +150,7 @@ it(':terminal highlight has lower precedence than editor #9964', function()
}, },
}) })
-- Child nvim process in :terminal (with cterm colors). -- Child nvim process in :terminal (with cterm colors).
fn.termopen({ fn.jobstart({
nvim_prog_abs(), nvim_prog_abs(),
'-n', '-n',
'-u', '-u',
@ -163,6 +163,7 @@ it(':terminal highlight has lower precedence than editor #9964', function()
'+norm! ichild nvim', '+norm! ichild nvim',
'+norm! oline 2', '+norm! oline 2',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -200,7 +201,7 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
[4] = { background = Screen.colors.Grey90, reverse = true }, [4] = { background = Screen.colors.Grey90, reverse = true },
[5] = { background = Screen.colors.Red }, [5] = { background = Screen.colors.Red },
}) })
command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
screen:expect([[ screen:expect([[
^tty ready | ^tty ready |
|*6 |*6
@ -318,7 +319,7 @@ describe(':terminal highlight forwarding', function()
[2] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } }, [2] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
[3] = { { foreground = tonumber('0xff8000') }, {} }, [3] = { { foreground = tonumber('0xff8000') }, {} },
}) })
command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i') feed('i')
screen:expect([[ screen:expect([[
tty ready | tty ready |
@ -364,7 +365,7 @@ describe(':terminal highlight with custom palette', function()
[9] = { bold = true }, [9] = { bold = true },
}) })
api.nvim_set_var('terminal_color_3', '#123456') api.nvim_set_var('terminal_color_3', '#123456')
command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i') feed('i')
screen:expect([[ screen:expect([[
tty ready | tty ready |

View File

@ -355,7 +355,9 @@ describe(':terminal prints more lines than the screen height and exits', functio
it('will push extra lines to scrollback', function() it('will push extra lines to scrollback', function()
clear() clear()
local screen = Screen.new(30, 7, { rgb = false }) local screen = Screen.new(30, 7, { rgb = false })
command(("call termopen(['%s', '10']) | startinsert"):format(testprg('tty-test'))) command(
("call jobstart(['%s', '10'], {'term':v:true}) | startinsert"):format(testprg('tty-test'))
)
screen:expect([[ screen:expect([[
line6 | line6 |
line7 | line7 |
@ -623,7 +625,7 @@ describe('pending scrollback line handling', function()
local bufnr = vim.api.nvim_create_buf(false, true) local bufnr = vim.api.nvim_create_buf(false, true)
local args = ... local args = ...
vim.api.nvim_buf_call(bufnr, function() vim.api.nvim_buf_call(bufnr, function()
vim.fn.termopen(args) vim.fn.jobstart(args, { term = true })
end) end)
vim.api.nvim_win_set_buf(0, bufnr) vim.api.nvim_win_set_buf(0, bufnr)
vim.cmd('startinsert') vim.cmd('startinsert')

View File

@ -2114,7 +2114,7 @@ describe('TUI', function()
[5] = { bold = true, reverse = true }, [5] = { bold = true, reverse = true },
[6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, [6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen },
}) })
fn.termopen({ fn.jobstart({
nvim_prog, nvim_prog,
'--clean', '--clean',
'--cmd', '--cmd',
@ -2124,6 +2124,7 @@ describe('TUI', function()
'--cmd', '--cmd',
'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },
@ -2146,7 +2147,7 @@ describe('TUI', function()
for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do
it('has no black flicker when clearing regions during startup with ' .. guicolors, function() it('has no black flicker when clearing regions during startup with ' .. guicolors, function()
local screen = Screen.new(50, 10) local screen = Screen.new(50, 10)
fn.termopen({ fn.jobstart({
nvim_prog, nvim_prog,
'--clean', '--clean',
'--cmd', '--cmd',
@ -2154,6 +2155,7 @@ describe('TUI', function()
'--cmd', '--cmd',
'sleep 10', 'sleep 10',
}, { }, {
term = true,
env = { env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'), VIMRUNTIME = os.getenv('VIMRUNTIME'),
}, },

View File

@ -141,7 +141,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
}) })
api.nvim_command('enew') api.nvim_command('enew')
api.nvim_call_function('termopen', { cmd, env and { env = env } or nil }) api.nvim_call_function('jobstart', { cmd, { term = true, env = (env and env or nil) } })
api.nvim_input('<CR>') api.nvim_input('<CR>')
local vim_errmsg = api.nvim_eval('v:errmsg') local vim_errmsg = api.nvim_eval('v:errmsg')
if vim_errmsg and '' ~= vim_errmsg then if vim_errmsg and '' ~= vim_errmsg then

View File

@ -224,7 +224,7 @@ describe('ext_hlstate detailed highlights', function()
[6] = { { foreground = tonumber('0x40ffff'), fg_indexed = true }, { 5, 1 } }, [6] = { { foreground = tonumber('0x40ffff'), fg_indexed = true }, { 5, 1 } },
[7] = { {}, { { hi_name = 'MsgArea', ui_name = 'MsgArea', kind = 'ui' } } }, [7] = { {}, { { hi_name = 'MsgArea', ui_name = 'MsgArea', kind = 'ui' } } },
}) })
command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) command(("enew | call jobstart(['%s'],{'term':v:true})"):format(testprg('tty-test')))
screen:expect([[ screen:expect([[
^tty ready | ^tty ready |
| |

View File

@ -2079,7 +2079,7 @@ describe('ui/msg_puts_printf', function()
) )
cmd = cmd .. '"' .. nvim_prog .. '" -u NONE -i NONE -Es -V1' cmd = cmd .. '"' .. nvim_prog .. '" -u NONE -i NONE -Es -V1'
command([[call termopen(']] .. cmd .. [[')]]) command([[call jobstart(']] .. cmd .. [[',{'term':v:true})]])
screen:expect([[ screen:expect([[
^Exモードに入ります | ^Exモードに入ります |
"vis| "vis|

View File

@ -80,7 +80,7 @@ describe('title', function()
it('is updated in Terminal mode', function() it('is updated in Terminal mode', function()
api.nvim_set_option_value('title', true, {}) api.nvim_set_option_value('title', true, {})
api.nvim_set_option_value('titlestring', '(%{mode(1)}) | nvim', {}) api.nvim_set_option_value('titlestring', '(%{mode(1)}) | nvim', {})
fn.termopen({ n.testprg('shell-test'), 'INTERACT' }) fn.jobstart({ n.testprg('shell-test'), 'INTERACT' }, { term = true })
screen:expect(function() screen:expect(function()
eq('(nt) | nvim', screen.title) eq('(nt) | nvim', screen.title)
end) end)

View File

@ -8,6 +8,7 @@ function s:logger.on_exit(id, data, event)
endfunction endfunction
let s:logger.env = #{VIMRUNTIME: $VIMRUNTIME} let s:logger.env = #{VIMRUNTIME: $VIMRUNTIME}
let s:logger.term = v:true
" Replace non-printable chars by special sequence, or "<%x>". " Replace non-printable chars by special sequence, or "<%x>".
let s:escaped_char = {"\n": '\n', "\r": '\r', "\t": '\t'} let s:escaped_char = {"\n": '\n', "\r": '\r', "\t": '\t'}
@ -25,7 +26,7 @@ function Main()
set lines=25 set lines=25
set columns=80 set columns=80
enew enew
let job = termopen(args, s:logger) let job = jobstart(args, s:logger)
let results = jobwait([job], 5 * 60 * 1000) let results = jobwait([job], 5 * 60 * 1000)
" TODO(ZyX-I): Get colors " TODO(ZyX-I): Get colors
let screen = getline(1, '$') let screen = getline(1, '$')