aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2020-02-12 00:24:50 -0800
committerGitHub <noreply@github.com>2020-02-12 00:24:50 -0800
commit68de6b17b8660adfeda93e46cec6ee6ebc7ebcf5 (patch)
tree8f60b4a224a943bdfe943c6395d210612212c351 /runtime
parent58ec72f9fdfd186e5154ce82be1da7c65b9c8ea0 (diff)
parentd54b5997b7472f6c8a6f224801e2cd2e8ddf017b (diff)
downloadrneovim-68de6b17b8660adfeda93e46cec6ee6ebc7ebcf5.tar.gz
rneovim-68de6b17b8660adfeda93e46cec6ee6ebc7ebcf5.tar.bz2
rneovim-68de6b17b8660adfeda93e46cec6ee6ebc7ebcf5.zip
Merge #10433 from erw7/vim-8.1.0027
vim-patch:8.1.{27,32,36,69,70,71,91,92}
Diffstat (limited to 'runtime')
-rw-r--r--runtime/doc/eval.txt58
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt17
-rw-r--r--runtime/doc/options.txt2
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim241
4 files changed, 299 insertions, 19 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index e0ce83f8d2..b8739ff9b3 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2084,6 +2084,7 @@ ctxsize() Number return |context-stack| size
cursor({lnum}, {col} [, {off}])
Number move cursor to {lnum}, {col}, {off}
cursor({list}) Number move cursor to position in {list}
+debugbreak({pid}) Number interrupt process being debugged
deepcopy({expr} [, {noref}]) any make a full copy of {expr}
delete({fname} [, {flags}]) Number delete the file or directory {fname}
deletebufline({expr}, {first}[, {last}])
@@ -2280,6 +2281,10 @@ pathshorten({expr}) String shorten directory names in a path
pow({x}, {y}) Float {x} to the power of {y}
prevnonblank({lnum}) Number line nr of non-blank line <= {lnum}
printf({fmt}, {expr1}...) String format text
+prompt_addtext({buf}, {expr}) none add text to a prompt buffer
+prompt_setcallback({buf}, {expr}) none set prompt callback function
+prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
+prompt_setprompt({buf}, {text}) none set prompt text
pum_getpos() Dict position and size of pum if visible
pumvisible() Number whether popup menu is visible
pyeval({expr}) any evaluate |Python| expression
@@ -2290,7 +2295,7 @@ range({expr} [, {max} [, {stride}]])
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
readfile({fname} [, {binary} [, {max}]])
List get list of lines from file {fname}
-reg_executing() Number get the executing register name
+reg_executing() String get the executing register name
reg_recording() String get the recording register name
reltime([{start} [, {end}]]) List get time value
reltimefloat({time}) Float turn the time value into a Float
@@ -3637,6 +3642,11 @@ exp({expr}) *exp()*
:echo exp(-1)
< 0.367879
+debugbreak({pid}) *debugbreak()*
+ Specifically used to interrupt a program being debugged. It
+ will cause process {pid} to get a SIGTRAP. Behavior for other
+ processes is undefined. See |terminal-debugger|.
+ {Sends a SIGINT to a process {pid} other than MS-Windows}
expand({expr} [, {nosuf} [, {list}]]) *expand()*
Expand wildcards and the following special keywords in {expr}.
@@ -4541,7 +4551,7 @@ getline({lnum} [, {end}])
from the current buffer. Example: >
getline(1)
< When {lnum} is a String that doesn't start with a
- digit, line() is called to translate the String into a Number.
+ digit, |line()| is called to translate the String into a Number.
To get the line under the cursor: >
getline(".")
< When {lnum} is smaller than 1 or bigger than the number of
@@ -6541,6 +6551,50 @@ printf({fmt}, {expr1} ...) *printf()*
of "%" items. If there are not sufficient or too many
arguments an error is given. Up to 18 arguments can be used.
+prompt_setcallback({buf}, {expr}) *prompt_setcallback()*
+ Set prompt callback for buffer {buf} to {expr}. When {expr}
+ is an empty string the callback is removed. This has only
+ effect if {buf} has 'buftype' set to "prompt".
+
+ The callback is invoked when pressing Enter. The current
+ buffer will always be the prompt buffer. A new line for a
+ prompt is added before invoking the callback, thus the prompt
+ for which the callback was invoked will be in the last but one
+ line.
+ If the callback wants to add text to the buffer, it must
+ insert it above the last line, since that is where the current
+ prompt is. This can also be done asynchronously.
+ The callback is invoked with one argument, which is the text
+ that was entered at the prompt. This can be an empty string
+ if the user only typed Enter.
+ Example: >
+ call prompt_setcallback(bufnr(''), function('s:TextEntered'))
+ func s:TextEntered(text)
+ if a:text == 'exit' || a:text == 'quit'
+ stopinsert
+ close
+ else
+ call append(line('$') - 1, 'Entered: "' . a:text . '"')
+ " Reset 'modified' to allow the buffer to be closed.
+ set nomodified
+ endif
+ endfunc
+
+prompt_setinterrupt({buf}, {expr}) *prompt_setinterrupt()*
+ Set a callback for buffer {buf} to {expr}. When {expr} is an
+ empty string the callback is removed. This has only effect if
+ {buf} has 'buftype' set to "prompt".
+
+ This callback will be invoked when pressing CTRL-C in Insert
+ mode. Without setting a callback Vim will exit Insert mode,
+ as in any buffer.
+
+prompt_setprompt({buf}, {text}) *prompt_setprompt()*
+ Set prompt for buffer {buf} to {text}. You most likely want
+ {text} to end in a space.
+ The result is only visible if {buf} has 'buftype' set to
+ "prompt". Example: >
+ call prompt_setprompt(bufnr(''), 'command: ')
pum_getpos() *pum_getpos()*
If the popup menu (see |ins-completion-menu|) is not visible,
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index 1a5e6421e7..55c5335a60 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -307,6 +307,23 @@ Other commands ~
isn't one
+Prompt mode ~
+ *termdebug-prompt*
+When on MS-Windows, gdb will run in a buffer with 'buftype' set to "prompt".
+This works slightly differently:
+- The gdb window will be in Insert mode while typing commands. Go to Normal
+ mode with <Esc>, then you can move around in the buffer, copy/paste, etc.
+ Go back to editing the gdb command with any command that starts Insert mode,
+ such as `a` or `i`.
+- The program being debugged will run in a separate window. On MS-Windows
+ this is a new console window. On Unix, if the |+terminal| feature is
+ available a Terminal window will be opened to run the debugged program in.
+
+ *termdebug_use_prompt*
+Prompt mode can be used even when the |+terminal| feature is present with: >
+ let g:termdebug_use_prompt = 1
+
+
Communication ~
*termdebug-communication*
There is another, hidden, buffer, which is used for Vim to communicate with
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 70af23ee29..7107a0135d 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1093,6 +1093,8 @@ A jump table for the options with a short description can be found at |Q_op|.
nowrite buffer will not be written
quickfix list of errors |:cwindow| or locations |:lwindow|
terminal |terminal-emulator| buffer
+ prompt buffer where only the last line can be edited, meant
+ to be used by a plugin, see |prompt-buffer|
This option is used together with 'bufhidden' and 'swapfile' to
specify special kinds of buffers. See |special-buffers|.
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 7a757ef7d6..aa2b69ad97 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -37,7 +37,7 @@
" For neovim compatibility, the vim specific calls were replaced with neovim
" specific calls:
" term_start -> term_open
-" term_sendkeys -> jobsend
+" term_sendkeys -> chansend
" term_getline -> getbufline
" job_info && term_getjob -> using linux command ps to get the tty
" balloon -> nvim floating window
@@ -47,8 +47,6 @@
" https://github.com/autozimu/LanguageClient-neovim/blob/0ed9b69dca49c415390a8317b19149f97ae093fa/autoload/LanguageClient.vim#L304
"
" Neovim terminal also works seamlessly on windows, which is why the ability
-" to use the prompt buffer was removed.
-"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
@@ -57,6 +55,12 @@ if exists(':Termdebug')
finish
endif
+" The terminal feature does not work with gdb on win32.
+if !has('win32')
+ let s:way = 'terminal'
+else
+ let s:way = 'prompt'
+endif
let s:keepcpo = &cpo
set cpo&vim
@@ -138,7 +142,19 @@ func s:StartDebug_internal(dict)
let s:vertical = 0
endif
- call s:StartDebug_term(a:dict)
+ " Override using a terminal window by setting g:termdebug_use_prompt to 1.
+ let use_prompt = exists('g:termdebug_use_prompt') && g:termdebug_use_prompt
+ if !has('win32') && !use_prompt
+ let s:way = 'terminal'
+ else
+ let s:way = 'prompt'
+ endif
+
+ if s:way == 'prompt'
+ call s:StartDebug_prompt(a:dict)
+ else
+ call s:StartDebug_term(a:dict)
+ endif
endfunc
" Use when debugger didn't start or ended.
@@ -214,11 +230,11 @@ func s:StartDebug_term(dict)
" Set arguments to be run
if len(proc_args)
- call jobsend(s:gdb_job_id, 'set args ' . join(proc_args) . "\r")
+ call chansend(s:gdb_job_id, 'set args ' . join(proc_args) . "\r")
endif
" Connect gdb to the communication pty, using the GDB/MI interface
- call jobsend(s:gdb_job_id, 'new-ui mi ' . commpty . "\r")
+ call chansend(s:gdb_job_id, 'new-ui mi ' . commpty . "\r")
" Wait for the response to show up, users may not notice the error and wonder
" why the debugger doesn't work.
@@ -275,6 +291,100 @@ func s:StartDebug_term(dict)
call s:StartDebugCommon(a:dict)
endfunc
+func s:StartDebug_prompt(dict)
+ " Open a window with a prompt buffer to run gdb in.
+ if s:vertical
+ vertical new
+ else
+ new
+ endif
+ let s:gdbwin = win_getid(winnr())
+ let s:promptbuf = bufnr('')
+ call prompt_setprompt(s:promptbuf, 'gdb> ')
+ set buftype=prompt
+ file gdb
+ call prompt_setcallback(s:promptbuf, function('s:PromptCallback'))
+ call prompt_setinterrupt(s:promptbuf, function('s:PromptInterrupt'))
+
+ if s:vertical
+ " Assuming the source code window will get a signcolumn, use two more
+ " columns for that, thus one less for the terminal window.
+ exe (&columns / 2 - 1) . "wincmd |"
+ endif
+
+ " Add -quiet to avoid the intro message causing a hit-enter prompt.
+ let gdb_args = get(a:dict, 'gdb_args', [])
+ let proc_args = get(a:dict, 'proc_args', [])
+
+ let cmd = [g:termdebugger, '-quiet', '--interpreter=mi2'] + gdb_args
+ "call ch_log('executing "' . join(cmd) . '"')
+
+ let s:gdbjob = jobstart(cmd, {
+ \ 'on_exit': function('s:EndPromptDebug'),
+ \ 'on_stdout': function('s:GdbOutCallback'),
+ \ })
+ if s:gdbjob == 0
+ echoerr 'invalid argument (or job table is full) while starting gdb job'
+ exe 'bwipe! ' . s:ptybuf
+ return
+ elseif s:gdbjob == -1
+ echoerr 'Failed to start the gdb job'
+ call s:CloseBuffers()
+ return
+ endif
+
+ " Interpret commands while the target is running. This should usualy only
+ " be exec-interrupt, since many commands don't work properly while the
+ " target is running.
+ call s:SendCommand('-gdb-set mi-async on')
+ " Older gdb uses a different command.
+ call s:SendCommand('-gdb-set target-async on')
+
+ let s:ptybuf = 0
+ if has('win32')
+ " MS-Windows: run in a new console window for maximum compatibility
+ call s:SendCommand('set new-console on')
+ else
+ " Unix: Run the debugged program in a terminal window. Open it below the
+ " gdb window.
+ execute 'new'
+ wincmd x | wincmd j
+ belowright let s:pty_job_id = termopen('tail -f /dev/null;#gdb program')
+ if s:pty_job_id == 0
+ echoerr 'invalid argument (or job table is full) while opening terminal window'
+ return
+ elseif s:pty_job_id == -1
+ echoerr 'Failed to open the program terminal window'
+ return
+ endif
+ let pty_job_info = nvim_get_chan_info(s:pty_job_id)
+ let s:ptybuf = pty_job_info['buffer']
+ let pty = pty_job_info['pty']
+ let s:ptywin = win_getid(winnr())
+ call s:SendCommand('tty ' . pty)
+
+ " Since GDB runs in a prompt window, the environment has not been set to
+ " match a terminal window, need to do that now.
+ call s:SendCommand('set env TERM = xterm-color')
+ call s:SendCommand('set env ROWS = ' . winheight(s:ptywin))
+ call s:SendCommand('set env LINES = ' . winheight(s:ptywin))
+ call s:SendCommand('set env COLUMNS = ' . winwidth(s:ptywin))
+ call s:SendCommand('set env COLORS = ' . &t_Co)
+ call s:SendCommand('set env VIM_TERMINAL = ' . v:version)
+ endif
+ call s:SendCommand('set print pretty on')
+ call s:SendCommand('set breakpoint pending on')
+ " Disable pagination, it causes everything to stop at the gdb
+ call s:SendCommand('set pagination off')
+
+ " Set arguments to be run
+ if len(proc_args)
+ call s:SendCommand('set args ' . join(proc_args))
+ endif
+
+ call s:StartDebugCommon(a:dict)
+ startinsert
+endfunc
func s:StartDebugCommon(dict)
" Sign used to highlight the line where the program has stopped.
@@ -316,23 +426,99 @@ endfunc
" Send a command to gdb. "cmd" is the string without line terminator.
func s:SendCommand(cmd)
"call ch_log('sending to gdb: ' . a:cmd)
- call jobsend(s:comm_job_id, a:cmd . "\r")
+ if s:way == 'prompt'
+ call chansend(s:gdbjob, a:cmd . "\n")
+ else
+ call chansend(s:comm_job_id, a:cmd . "\r")
+ endif
endfunc
" This is global so that a user can create their mappings with this.
func TermDebugSendCommand(cmd)
- let do_continue = 0
- if !s:stopped
- let do_continue = 1
- call s:SendCommand('-exec-interrupt')
- sleep 10m
+ if s:way == 'prompt'
+ call chansend(s:gdbjob, a:cmd . "\n")
+ else
+ let do_continue = 0
+ if !s:stopped
+ let do_continue = 1
+ if s:way == 'prompt'
+ " Need to send a signal to get the UI to listen. Strangely this is only
+ " needed once.
+ call jobstop(s:gdbjob)
+ else
+ call s:SendCommand('-exec-interrupt')
+ endif
+ sleep 10m
+ endif
+ call chansend(s:gdb_job_id, a:cmd . "\r")
+ if do_continue
+ Continue
+ endif
endif
- call jobsend(s:gdb_job_id, a:cmd . "\r")
- if do_continue
- Continue
+endfunc
+
+" Function called when entering a line in the prompt buffer.
+func s:PromptCallback(text)
+ call s:SendCommand(a:text)
+endfunc
+
+" Function called when pressing CTRL-C in the prompt buffer and when placing a
+" breakpoint.
+func s:PromptInterrupt()
+ if s:pid == 0
+ echoerr 'Cannot interrupt gdb, did not find a process ID'
+ else
+ "call ch_log('Interrupting gdb')
+ " Using job_stop(s:gdbjob, 'int') does not work.
+ call debugbreak(s:pid)
endif
endfunc
+" Function called when gdb outputs text.
+func s:GdbOutCallback(job_id, msgs, event)
+ "call ch_log('received from gdb: ' . a:text)
+
+ " Drop the gdb prompt, we have our own.
+ " Drop status and echo'd commands.
+ call filter(a:msgs, { index, val ->
+ \ val !=# '(gdb)' && val !=# '^done' && val[0] !=# '&'})
+
+ let lines = []
+ let index = 0
+
+ for msg in a:msgs
+ if msg =~ '^^error,msg='
+ if exists('s:evalexpr')
+ \ && s:DecodeMessage(msg[11:])
+ \ =~ 'A syntax error in expression, near\|No symbol .* in current context'
+ " Silently drop evaluation errors.
+ call remove(a:msgs, index)
+ unlet s:evalexpr
+ continue
+ endif
+ elseif msg[0] == '~'
+ call add(lines, s:DecodeMessage(msg[1:]))
+ call remove(a:msgs, index)
+ continue
+ endif
+ let index += 1
+ endfor
+
+ let curwinid = win_getid(winnr())
+ call win_gotoid(s:gdbwin)
+
+ " Add the output above the current prompt.
+ for line in lines
+ call append(line('$') - 1, line)
+ endfor
+ if !empty(lines)
+ set modified
+ endif
+
+ call win_gotoid(curwinid)
+ call s:CommOutput(a:job_id, a:msgs, a:event)
+endfunc
+
" Decode a message from gdb. quotedText starts with a ", return the text up
" to the next ", unescaping characters.
func s:DecodeMessage(quotedText)
@@ -396,6 +582,19 @@ func s:EndDebugCommon()
au! TermDebug
endfunc
+func s:EndPromptDebug(job_id, exit_code, event)
+ let curwinid = win_getid(winnr())
+ call win_gotoid(s:gdbwin)
+ close
+ if curwinid != s:gdbwin
+ call win_gotoid(curwinid)
+ endif
+
+ call s:EndDebugCommon()
+ unlet s:gdbwin
+ "call ch_log("Returning from EndPromptDebug()")
+endfunc
+
func s:CommOutput(job_id, msgs, event)
for msg in a:msgs
@@ -436,7 +635,11 @@ func s:InstallCommands()
command Stop call s:SendCommand('-exec-interrupt')
" using -exec-continue results in CTRL-C in gdb window not working
- command Continue call jobsend(s:gdb_job_id, "continue\r")
+ if s:way == 'prompt'
+ command Continue call s:SendCommand('continue')
+ else
+ command Continue call chansend(s:gdb_job_id, "continue\r")
+ endif
command -range -nargs=* Evaluate call s:Evaluate(<range>, <q-args>)
command Gdb call win_gotoid(s:gdbwin)
@@ -494,7 +697,11 @@ func s:SetBreakpoint()
let do_continue = 0
if !s:stopped
let do_continue = 1
- call s:SendCommand('-exec-interrupt')
+ if s:way == 'prompt'
+ call s:PromptInterrupt()
+ else
+ call s:SendCommand('-exec-interrupt')
+ endif
sleep 10m
endif
" Use the fname:lnum format, older gdb can't handle --source.