From 9b62ebeba813f92929671cbf84b850f7a382bb93 Mon Sep 17 00:00:00 2001 From: Rafal Marguzewicz Date: Sun, 4 Aug 2019 20:56:51 +0200 Subject: [PATCH 01/47] Changes Remove unused packages: 1 dbgp.py|2 col 1 error| 'socket' imported but unused [F401] [python/flake8] 2 dbgp.py|3 col 1 error| 'sys' imported but unused [F401] [python/flake8] 3 dbgp.py|4 col 1 error| 'time' imported but unused [F401] [python/flake8] Standard PEP8: 4 dbgp.py|162 col 28 error| E225 missing whitespace around operator [python/pep8] 5 dbgp.py|162 col 28 error| missing whitespace around operator [E225] [python/flake8] 6 dbgp.py|254 col 28 error| E226 missing whitespace around arithmetic operator [python/pep8] 7 dbgp.py|254 col 28 error| missing whitespace around arithmetic operator [E226] [python/flake8] 8 dbgp.py|257 col 29 error| E226 missing whitespace around arithmetic operator [python/pep8] 9 dbgp.py|257 col 29 error| missing whitespace around arithmetic operator [E226] [python/flake8] 10 dbgp.py|276 col 50 error| E226 missing whitespace around arithmetic operator [python/pep8] Changes to be committed: modified: python3/vdebug/dbgp.py --- python3/vdebug/dbgp.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/python3/vdebug/dbgp.py b/python3/vdebug/dbgp.py index bfa2ec83..599899bd 100644 --- a/python3/vdebug/dbgp.py +++ b/python3/vdebug/dbgp.py @@ -1,7 +1,4 @@ import base64 -import socket -import sys -import time import xml.etree.ElementTree as ET from . import log @@ -159,7 +156,7 @@ def get_code(self): parts = cmd.split('-- ') missing_padding = len(parts[1]) % 4 if missing_padding != 0: - parts[1] += '='* (4 - missing_padding) + parts[1] += '=' * (4 - missing_padding) return base64.b64decode(parts[1].encode('utf-8')).decode('utf-8') @@ -251,10 +248,10 @@ def send_cmd(self, cmd, args='', res_cls=Response): send += ' -i ' + str(self.transID) if args: send += ' ' + args - log.Log("Command: "+send, log.Logger.DEBUG) + log.Log("Command: " + send, log.Logger.DEBUG) self.conn.send_msg(send) msg = self.conn.recv_msg() - log.Log("Response: "+msg, log.Logger.DEBUG) + log.Log("Response: " + msg, log.Logger.DEBUG) return res_cls(msg, cmd, args, self) def status(self): @@ -273,7 +270,7 @@ def feature_get(self, name): name -- name of the feature, e.g. encoding """ - return self.send_cmd('feature_get', '-n '+str(name), + return self.send_cmd('feature_get', '-n ' + str(name), FeatureGetResponse) def feature_set(self, name, value): @@ -486,7 +483,7 @@ def __init_children(self, node): for c in children: if c.tag == tagname: idx += 1 - p = self._create_child(c, self, self.depth+1) + p = self._create_child(c, self, self.depth + 1) self.children.append(p) if idx == self.num_declared_children: p.mark_as_last_child() @@ -539,7 +536,7 @@ def _determine_displayname(self, node): "['%s']" % node.get('name') else: self.display_name = self.parent.display_name + \ - "->"+node.get('name') + "->" + node.get('name') elif self.language == 'perl': self.display_name = node.get('fullname') else: From 836a724bff1abddea34ad41521e0cb54cf03d8f7 Mon Sep 17 00:00:00 2001 From: determin1st Date: Sun, 6 Oct 2019 17:41:19 +0500 Subject: [PATCH 02/47] fixes startup issue on win7 --- plugin/vdebug.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 8d7962bc..98b939b3 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -105,6 +105,7 @@ if g:vdebug_force_ascii == 1 let g:vdebug_options_defaults['marker_open_tree'] = '-' let g:vdebug_options_defaults['sign_breakpoint'] = 'B>' let g:vdebug_options_defaults['sign_current'] = '->' + let g:vdebug_options_defaults['sign_disabled'] = 'B|' endif " Create the top dog From 2a5a8744e54db4a6f8e0ec6ab602e0f11e78267a Mon Sep 17 00:00:00 2001 From: baptx Date: Fri, 8 Nov 2019 12:11:35 +0100 Subject: [PATCH 03/47] clarify that the master branch is based on version 2.0.0, not 1.4.1 #430 --- plugin/vdebug.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 8d7962bc..3e1ac3a5 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -8,7 +8,7 @@ " Description: Multi-language debugger client for Vim (PHP, Ruby, Python, " Perl, NodeJS) " Maintainer: Jon Cairns -" Version: 1.4.1 +" Version: 2.0.0 " Inspired by the Xdebug plugin, which was originally written by " Seung Woo Shin sayclub.com> and extended by many " others. From 04a8c7336e266fa2eccc533adf1bfcf5ba92b491 Mon Sep 17 00:00:00 2001 From: Scott Tester Date: Fri, 15 Nov 2019 20:01:00 +1100 Subject: [PATCH 04/47] Fix #423 - Vim Hangs on exit if vdebug is running. --- plugin/vdebug.vim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 8d7962bc..76d0f5fa 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -314,6 +314,8 @@ function! Vdebug_statusline() endfunction augroup Vdebug +augroup END +augroup VdebugOut autocmd VimLeavePre * python3 debugger.close() augroup END From 1a38eced72d9b13d69e7a2a0e721e54e75212b7d Mon Sep 17 00:00:00 2001 From: JJP7 Date: Tue, 4 Feb 2020 13:14:31 +0800 Subject: [PATCH 05/47] added comma --- python3/vdebug/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vdebug/util.py b/python3/vdebug/util.py index 653705e6..4332e7ef 100644 --- a/python3/vdebug/util.py +++ b/python3/vdebug/util.py @@ -105,7 +105,7 @@ class Keymapper: """ exclude = ["run", "close", "set_breakpoint", "enable_breakpoint", "disable_breakpoint", - "toggle_breakpoint" "eval_visual"] + "toggle_breakpoint", "eval_visual"] def __init__(self): self.is_mapped = False From 3b6b86521b6617ee45d06a06adf533c46bb570d0 Mon Sep 17 00:00:00 2001 From: guantion Date: Sat, 29 Feb 2020 10:46:19 +0800 Subject: [PATCH 06/47] fix log and breakpoint miss hit on win os --- python3/vdebug/log.py | 4 +++- python3/vdebug/util.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python3/vdebug/log.py b/python3/vdebug/log.py index 5dadea35..7db9a5ff 100644 --- a/python3/vdebug/log.py +++ b/python3/vdebug/log.py @@ -81,7 +81,7 @@ def __init__(self, debug_level, filename): def __open(self): try: - self.f = open(self.filename, 'w') + self.f = open(self.filename, 'w', encoding='utf-8') except IOError as e: raise error.LogError("Invalid file name '%s' for log file: %s" % (self.filename, e)) @@ -104,6 +104,8 @@ class Log: loggers = {} + + def __init__(self, string, level=Logger.INFO): Log.log(string, level) diff --git a/python3/vdebug/util.py b/python3/vdebug/util.py index 4332e7ef..09bf48fb 100644 --- a/python3/vdebug/util.py +++ b/python3/vdebug/util.py @@ -278,7 +278,8 @@ def as_local(self, quote=False): return self.local def as_remote(self): - return self.remote + # on win os backslash will cost breakpoint miss hit + return self.remote.replace('\\', '/') if self.is_win else self.remote @staticmethod def _findSeparator(path): From 4b12452a35d7d7bbf824765015333cab3143fe52 Mon Sep 17 00:00:00 2001 From: guantion Date: Fri, 20 Mar 2020 22:37:11 +0800 Subject: [PATCH 07/47] update test --- tests/test_log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_log.py b/tests/test_log.py index 821f6205..b68fa7c0 100644 --- a/tests/test_log.py +++ b/tests/test_log.py @@ -89,7 +89,7 @@ def setUp(self): def test_log_opens_file(self): with mock.patch(self.open_name, mock.mock_open()) as mocked_open: self.logger.log('text', self.level) - mocked_open.assert_called_once_with(self.filename, 'w') + mocked_open.assert_called_once_with(self.filename, 'w', encoding='utf-8') handle = mocked_open() if sys.version_info[0] >= 3 and sys.version_info[1] >= 6: handle.write.assert_called_once() @@ -115,6 +115,6 @@ def test_shutdown_with_file(self): with mock.patch(self.open_name, mock.mock_open()) as mocked_open: self.logger.log('text', self.level) self.logger.shutdown() - mocked_open.assert_called_once_with(self.filename, 'w') + mocked_open.assert_called_once_with(self.filename, 'w', encoding='utf-8') handle = mocked_open() handle.close.assert_called_once_with() From 6d724f069e6afb8d079b92ff6085faaf1c1e21fd Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Mon, 23 Mar 2020 00:28:17 +0100 Subject: [PATCH 08/47] JUMPING FROM BREAKPOINT WINDOW TO BREAKPOINT IN SOURCE WINDOW There seems to be a small bug that whenever the stack contains only one item, the jumping does not work. This is also the case for the stack jump. --- .gitignore | 1 + python3/vdebug/debugger_interface.py | 5 +++++ python3/vdebug/event.py | 33 ++++++++++++++++++++++++++++ python3/vdebug/ui/vimui.py | 4 ++++ 4 files changed, 43 insertions(+) diff --git a/.gitignore b/.gitignore index 758b86e2..3b4c0049 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ vendor/ .bash_history Gemfile.lock .gem/ +tags diff --git a/python3/vdebug/debugger_interface.py b/python3/vdebug/debugger_interface.py index 0a8530d6..61fe421d 100644 --- a/python3/vdebug/debugger_interface.py +++ b/python3/vdebug/debugger_interface.py @@ -147,6 +147,11 @@ def remove_breakpoint(self, args=None): """ self.session_handler.dispatch_event("remove_breakpoint", args) + def jump_breakpoint(self, args=None): + """Jump to a breakpoint in the source window from the breakpoint window + """ + self.session_handler.dispatch_event("breakpoint_jump", args) + def get_context(self): """Get all the variables in the default context """ diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 303e1dc9..aa625523 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -512,6 +512,34 @@ def run(self, args): if action == "toggle": return self.dispatch("toggle_breakpoint", str(bp.id)) +class BreakpointJumpEvent(BreakpointStatusEvent): + + """Event used to trigger the source window change to the breakpoint + + The id of the breakpoint under the VIM cursor is retrieved, and the source file + and line number are set with the breakpoint data. + """ + + def run(self): + lineno = vim.current.window.cursor[0] + + log.Log("User action in breakpoint window, line %s" % lineno, + log.Logger.DEBUG) + line = self.ui.windows.breakpoints().line_at(lineno - 1) + + # Match on ID + id = re.findall('^[\s][0-9]*[\s]', line) + if not id: + return False + + bp = self.get_breakpoint(id[0].strip()) + + if bp is not None and bp.type == "line": + file = bp.get_file() + lineno = bp.get_line() + self.ui.sourcewin.set_file(file) + self.ui.sourcewin.set_line(lineno) + class CycleBreakpointStatusEvent(BreakpointStatusEvent): @@ -704,6 +732,7 @@ class Dispatcher: "enable_breakpoint": EnableBreakpointEvent, "disable_breakpoint": DisableBreakpointEvent, "breakpoint_status": BreakpointStatusEvent, + "breakpoint_jump": BreakpointJumpEvent, "get_context": GetContextEvent, "reload_keymappings": ReloadKeymappingsEvent, "remove_breakpoint": RemoveBreakpointEvent, @@ -765,3 +794,7 @@ def _get_event_by_position(session): return WatchWindowHideEvent(session) elif window_name == session.ui().windows.stack().name: return StackWindowLineSelectEvent(session) + elif window_name == session.ui().windows.breakpoints().name: + lineno = vim.current.window.cursor[0] + if lineno > 3: + return BreakpointJumpEvent(session) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 415e4c94..b123cee7 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -620,6 +620,10 @@ class BreakpointWindow(Window): def on_create(self): if self.creation_count == 1: self.insert(self.header, 0) + self.command('inoremap ' + ':python3 debugger.handle_return_keypress()') + self.command('nnoremap ' + ':python3 debugger.handle_return_keypress()') self.command('setlocal syntax=debugger_breakpoint') def add_breakpoint(self, breakpoint): From 80b10a9908459235c16eab07e7330497b6155c7f Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Mon, 23 Mar 2020 16:35:33 +0100 Subject: [PATCH 09/47] SOURCE WINDOW JUMPS TO CORRECT BUFFER WHEN THE SOURCE WINDOW BUFFER IS SWITCHED MANUALLY #444 --- python3/vdebug/ui/vimui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 415e4c94..71787747 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -364,11 +364,13 @@ def command(self, cmd, silent=True): vim.command(command_str) def set_file(self, file): - if file == self.file: + self.focus() + + if file == self.file and self.file == vim.current.buffer.name: return + self.file = file log.Log("Setting source file: %s" % file, log.Logger.INFO) - self.focus() vim.command('call Vdebug_edit("%s")' % str(file).replace("\\", "\\\\")) def set_line(self, lineno): From 4fe759cf343201ef6fac77c68d59613068788f35 Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Mon, 23 Mar 2020 17:38:19 +0100 Subject: [PATCH 10/47] DD IN BREAKPOINT WINDOW DELETES THE BREAKPOINT --- python3/vdebug/debugger_interface.py | 5 ++++ python3/vdebug/event.py | 35 +++++++++++++++++++++++----- python3/vdebug/ui/vimui.py | 4 ++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/python3/vdebug/debugger_interface.py b/python3/vdebug/debugger_interface.py index 0a8530d6..4d383336 100644 --- a/python3/vdebug/debugger_interface.py +++ b/python3/vdebug/debugger_interface.py @@ -74,6 +74,11 @@ def handle_return_keypress(self): """ return self.event_dispatcher.by_position(self.session_handler) + def handle_delete_line_keypress(self): + """React to a
keypress event. + """ + return self.event_dispatcher.delete_line(self.session_handler) + def handle_double_click(self): """React to a mouse double click event. """ diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 303e1dc9..941a6102 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -743,15 +743,27 @@ def by_position(self, session): log.Logger.DEBUG) return False + def delete_line(self, session): + window_name = self._get_window_name() + + if window_name == session.ui().windows.breakpoints().name: + lineno = vim.current.window.cursor[0] + if lineno > 3: + line = session.ui().windows.breakpoints().line_at(lineno - 1) + + # Match on ID + id = re.findall('^[\s][0-9]*[\s]', line) + if not id: + log.Log("No breakpoint founr at current cursor position", + log.Logger.DEBUG) + return False + + RemoveBreakpointEvent(session).run(id[0]) + @staticmethod def _get_event_by_position(session): - buf_name = vim.current.buffer.name - p = re.compile(r'.*[\\/]([^\\/]+)') - m = p.match(buf_name) - if m is None: - return None + window_name = Dispatcher._get_window_name() - window_name = m.group(1) if window_name == session.ui().windows.watch().name: lineno = vim.current.window.cursor[0] log.Log("User action in watch window, line %s" % lineno, @@ -765,3 +777,14 @@ def _get_event_by_position(session): return WatchWindowHideEvent(session) elif window_name == session.ui().windows.stack().name: return StackWindowLineSelectEvent(session) + + @staticmethod + def _get_window_name(): + buf_name = vim.current.buffer.name + p = re.compile(r'.*[\\/]([^\\/]+)') + m = p.match(buf_name) + if m is None: + return False + + window_name = m.group(1) + return window_name diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 415e4c94..1522e663 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -620,6 +620,10 @@ class BreakpointWindow(Window): def on_create(self): if self.creation_count == 1: self.insert(self.header, 0) + self.command('inoremap dd ' + ':python3 debugger.handle_delete_line_keypress()') + self.command('nnoremap dd ' + ':python3 debugger.handle_delete_line_keypress()') self.command('setlocal syntax=debugger_breakpoint') def add_breakpoint(self, breakpoint): From 74a46540435a03ff9473ef751327c954a56c8799 Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Mon, 23 Mar 2020 18:54:42 +0100 Subject: [PATCH 11/47] VISUAL DELETE BREAKPOINTS FROM BREAKPOINTWINDOW --- python3/vdebug/debugger_interface.py | 5 +++++ python3/vdebug/event.py | 20 ++++++++++++++++++++ python3/vdebug/ui/vimui.py | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/python3/vdebug/debugger_interface.py b/python3/vdebug/debugger_interface.py index 4d383336..29ba751b 100644 --- a/python3/vdebug/debugger_interface.py +++ b/python3/vdebug/debugger_interface.py @@ -79,6 +79,11 @@ def handle_delete_line_keypress(self): """ return self.event_dispatcher.delete_line(self.session_handler) + def handle_delete_visual_keypress(self): + """React to a vunmap keypress event. + """ + return self.event_dispatcher.delete_visual(self.session_handler) + def handle_double_click(self): """React to a mouse double click event. """ diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 941a6102..154d2350 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -760,6 +760,26 @@ def delete_line(self, session): RemoveBreakpointEvent(session).run(id[0]) + def delete_visual(self, session): + window_name = self._get_window_name() + + if window_name == session.ui().windows.breakpoints().name: + buf = vim.current.buffer + (lnum1, col1) = buf.mark('<') + (lnum2, col2) = buf.mark('>') + + lines = vim.eval('getline({}, {})'.format(lnum1, lnum2)) + + for line in lines: + # Match on ID + id = re.findall('^[\s][0-9]*[\s]', line) + if not id: + log.Log("No breakpoint founr at current cursor position", + log.Logger.DEBUG) + continue + + RemoveBreakpointEvent(session).run(id[0]) + @staticmethod def _get_event_by_position(session): window_name = Dispatcher._get_window_name() diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 1522e663..8891112b 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -624,6 +624,10 @@ def on_create(self): ':python3 debugger.handle_delete_line_keypress()') self.command('nnoremap dd ' ':python3 debugger.handle_delete_line_keypress()') + self.command('vnoremap d ' + ':python3 debugger.handle_delete_visual_keypress()') + self.command('xnoremap d ' + ':python3 debugger.handle_delete_visual_keypress()') self.command('setlocal syntax=debugger_breakpoint') def add_breakpoint(self, breakpoint): From 55858ae7810c43637238af223b16bc4b7e7bb7fa Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Sat, 28 Mar 2020 23:25:02 +0100 Subject: [PATCH 12/47] Breakpoint toggle added to breakpoint window + command --- .gitignore | 1 + plugin/vdebug.vim | 1 + python3/vdebug/event.py | 41 +++++++++++++++++++++++++++++++------- python3/vdebug/ui/vimui.py | 41 +++++++++++++++++++++++++++----------- 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 758b86e2..3b4c0049 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ vendor/ .bash_history Gemfile.lock .gem/ +tags diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index feb9fb8f..563de725 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -118,6 +118,7 @@ command! -nargs=? -complete=customlist,s:BreakpointTypes Breakpoint python3 debu command! -nargs=? -complete=customlist,s:BreakpointTypes SetBreakpoint python3 debugger.set_breakpoint() command! VdebugStart python3 debugger.run() command! -nargs=? BreakpointRemove python3 debugger.remove_breakpoint() +command! -nargs=? BreakpointToggle python3 debugger.toggle_breakpoint() command! BreakpointWindow python3 debugger.toggle_breakpoint_window() command! -nargs=? -bang VdebugEval python3 debugger.handle_eval('', ) command! -nargs=+ -complete=customlist,s:OptionNames VdebugOpt :call Vdebug_set_option() diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 154d2350..a3ba0eae 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -443,6 +443,22 @@ def run(self, args): self.session_handler.breakpoints().remove_breakpoint_by_id(id) return + # If in the breakpoint window, toggle breakpoint instead of adding/deleting one + window_name = Dispatcher._get_window_name() + if window_name == self.session_handler.ui().windows.breakpoints().name: + lineno = vim.current.window.cursor[0] + line = self.session_handler.ui().windows.breakpoints().line_at(lineno - 1) + id = Dispatcher._get_breakpoint_id_breakpoint_window(line) + if not id: + log.Log("No breakpoint founr at current cursor position", + log.Logger.DEBUG) + return + + self.session_handler.dispatch_event("toggle_breakpoint", "{} {}".format(id, "toggle")) + + return + + bp = breakpoint.Breakpoint.parse(self.ui, args) if bp.type == "line": id = self.session_handler.breakpoints().find_breakpoint( @@ -719,6 +735,8 @@ def __init__(self, session_handler): def dispatch_event(self, name, *args): try: + log.Log("Dispatching {} event".format(name), + log.Logger.INFO) Dispatcher.events[name](self.__session_handler).run(*args) except Exception as e: self.__ex_handler.handle(e) @@ -751,14 +769,13 @@ def delete_line(self, session): if lineno > 3: line = session.ui().windows.breakpoints().line_at(lineno - 1) - # Match on ID - id = re.findall('^[\s][0-9]*[\s]', line) + id = self._get_breakpoint_id_breakpoint_window(line) if not id: log.Log("No breakpoint founr at current cursor position", log.Logger.DEBUG) return False - RemoveBreakpointEvent(session).run(id[0]) + RemoveBreakpointEvent(session).run(id) def delete_visual(self, session): window_name = self._get_window_name() @@ -771,14 +788,13 @@ def delete_visual(self, session): lines = vim.eval('getline({}, {})'.format(lnum1, lnum2)) for line in lines: - # Match on ID - id = re.findall('^[\s][0-9]*[\s]', line) + id = self._get_breakpoint_id_breakpoint_window(line) if not id: log.Log("No breakpoint founr at current cursor position", log.Logger.DEBUG) - continue + return False - RemoveBreakpointEvent(session).run(id[0]) + RemoveBreakpointEvent(session).run(id) @staticmethod def _get_event_by_position(session): @@ -808,3 +824,14 @@ def _get_window_name(): window_name = m.group(1) return window_name + + @staticmethod + def _get_breakpoint_id_breakpoint_window(line): + # Match on ID + id = re.findall('^[\s][0-9]*[\s]', line) + if not id: + log.Log("No breakpoint founr at current cursor position", + log.Logger.DEBUG) + return False + + return id[0] diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 8891112b..060d30b4 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -278,9 +278,11 @@ def place_breakpoint(sign_id, file, line): def enable_breakpoint(self, breakpoint): self.place_breakpoint(breakpoint.id, breakpoint.file, breakpoint.line) + self.windows.breakpoints().update_breakpoint(breakpoint) def disable_breakpoint(self, breakpoint): self.place_disabled_breakpoint(breakpoint.id, breakpoint.file, breakpoint.line) + self.windows.breakpoints().update_breakpoint(breakpoint) @staticmethod def place_disabled_breakpoint(sign_id, file, line): @@ -614,7 +616,7 @@ class BreakpointWindow(Window): name = "DebuggerBreakpoints" header = """=========================================================== - ID | TYPE | DATA + ID | ACTIVE | TYPE | DATA ===========================================================""" def on_create(self): @@ -631,17 +633,7 @@ def on_create(self): self.command('setlocal syntax=debugger_breakpoint') def add_breakpoint(self, breakpoint): - bp_str = " %-7i | %-11s | " % (breakpoint.id, breakpoint.type) - if breakpoint.type == 'line': - bp_str += "%s:%s" % (breakpoint.file, str(breakpoint.line)) - elif breakpoint.type == 'conditional': - bp_str += "%s:%s when (%s)" % ( - breakpoint.file, str(breakpoint.line), breakpoint.condition) - elif breakpoint.type == 'exception': - bp_str += "Exception: %s" % breakpoint.exception - elif breakpoint.type == 'call' or breakpoint.type == 'return': - bp_str += "Function: %s" % breakpoint.function - + bp_str = self.breakpoint_str(breakpoint) self.write(bp_str) def remove_breakpoint(self, breakpoint_id): @@ -653,6 +645,31 @@ def remove_breakpoint(self, breakpoint_id): self._buffer.delete(i) i += 1 + def update_breakpoint(self, breakpoint): + i = 0 + for l in self._buffer.contents(): + bp_str = " %i " % breakpoint.id + bp_id_len = len(bp_str) + if l[:bp_id_len] == bp_str: + + bp_str = self.breakpoint_str(breakpoint) + self.insert(bp_str, i, True, True) + i += 1 + + def breakpoint_str(self, breakpoint): + bp_str = " %-7i | %-6s | %-11s | " % (breakpoint.id, breakpoint.enabled, breakpoint.type) + if breakpoint.type == 'line': + bp_str += "%s:%s" % (breakpoint.file, str(breakpoint.line)) + elif breakpoint.type == 'conditional': + bp_str += "%s:%s when (%s)" % ( + breakpoint.file, str(breakpoint.line), breakpoint.condition) + elif breakpoint.type == 'exception': + bp_str += "Exception: %s" % breakpoint.exception + elif breakpoint.type == 'call' or breakpoint.type == 'return': + bp_str += "Function: %s" % breakpoint.function + + return bp_str + class LogWindow(Window): From 5a3507ff230d495a2b1df5f26883af9c28c7da90 Mon Sep 17 00:00:00 2001 From: cos Date: Mon, 20 Apr 2020 19:46:39 +0200 Subject: [PATCH 13/47] Improve pathogen install instructions New phrasing mentions both of the commands required for pathogen to pick up vdebug in an empty vimrc. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e7bf65f0..53ed166d 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,9 @@ The actual installation is no different than for any other Vim plugin, you can * install manually: Clone or download a tarball of the plugin and move its content in your `~/.vim/` directory. You should call `:helptags ~/.vim/doc` to generate the necessary help tags afterwards. -* use Pathogen: Clone this repository to your `~/.vim/bundle` directory and - `:call pathogen#helptags()` afterwards. +* use Pathogen: Clone this repository to your `~/.vim/bundle` directory, run + `:execute pathogen#infect()` and `:call pathogen#helptags()` afterwards. + * use your favorite plugin manager: Put the respective instruction in your init file and update your plugins afterwards. For Vundle this would be `Plugin 'vim-vdebug/vdebug'` and `:PluginInstall`. From 9526e656e3bbca35f0d88c1fdca8b4c9fc31c655 Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Mon, 20 Apr 2020 21:18:28 +0200 Subject: [PATCH 14/47] Revert: add tags to gitignore Signed-off-by: BlackEagle --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3b4c0049..758b86e2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,3 @@ vendor/ .bash_history Gemfile.lock .gem/ -tags From 48efc2fb89776f5027d7eff6ef5860a61e48535c Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Tue, 21 Apr 2020 09:30:00 +0200 Subject: [PATCH 15/47] breakpoint jump can go to conditional too because that also has a line Signed-off-by: BlackEagle --- python3/vdebug/event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 63cc5a87..8bf09bc8 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -550,7 +550,7 @@ def run(self): bp = self.get_breakpoint(id[0].strip()) - if bp is not None and bp.type == "line": + if bp is not None and (bp.type == "line" or bp.type == "conditional"): file = bp.get_file() lineno = bp.get_line() self.ui.sourcewin.set_file(file) From 3c4df36e3213066f0832b2b80e215909db11e6c2 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Sat, 25 Apr 2020 17:33:17 +0200 Subject: [PATCH 16/47] Define highlights for DbgDisabledLine and DbgDisabledSign --- plugin/vdebug.vim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 563de725..b240fc8f 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -139,6 +139,12 @@ end if hlexists('DbgBreakptSign') == 0 hi default DbgBreakptSign term=reverse ctermfg=White ctermbg=Green guifg=#ffffff guibg=#00ff00 end +if hlexists('DbgDisabledLine') == 0 + highlight DbgDisabledLine term=reverse ctermbg=White ctermfg=Cyan guibg=#b4ee9a guifg=#888888 +endif +if hlexists('DbgDisabledSign') == 0 + highlight DbgDisabledSign term=reverse ctermbg=White ctermfg=Cyan guibg=#b4ee9a guifg=#888888 +endif " Signs and highlighted lines for breakpoints, etc. function! s:DefineSigns() From 348bfeefb08cd8f081d3cd0d2838d6bb8e0d4b11 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Sun, 26 Apr 2020 12:51:54 +0200 Subject: [PATCH 17/47] Set high priority for the `current` sign --- python3/vdebug/ui/vimui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 9bf308e2..a87a64c6 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -388,7 +388,7 @@ def get_file(self): def place_pointer(self, line): log.Log("Placing pointer sign on line "+str(line), log.Logger.INFO) self.remove_pointer() - vim.command('sign place %s name=current line=%s file=%s' + vim.command('sign place %s name=current priority=99 line=%s file=%s' % (self.pointer_sign_id, line, self.file)) def remove_pointer(self): From 66f3488737ae6605494a70e00da992966a2591ec Mon Sep 17 00:00:00 2001 From: Tom Stock Date: Sat, 2 May 2020 10:41:59 +0200 Subject: [PATCH 18/47] Documentation updated and visual toggle added in the breakpoint window --- doc/Vdebug.txt | 13 +++++++++++ python3/vdebug/debugger_interface.py | 5 +++- python3/vdebug/event.py | 35 ++++++++++++++++++---------- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 54f7a1be..9e0a6fef 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -538,6 +538,15 @@ To open the window use the command :BreakpointWindow. It's in a table format, so hopefully it won't need any more explanation. To close the window again, just re-type :BreakpointWindow or :q. +In this window while on the line of a breakpoint you can: + - Jump to a breakpoint by pressing + - Toggle a breakpoint by pressing (default) + - Delete a breakpoint by pressing
+ +In this window while visually selecting multiple breakpoints you can: + - Delete multiple breakpoints by pressing + - Toggle multiple breakpoints by pressing (default) + To see more about breakpoints see |VdebugBreakpoints|. ------------------------------------------------------------------------------ @@ -739,6 +748,10 @@ To remove all breakpoints in one go use the command: > :BreakpointRemove * < +In the breakpoint window a breakpoint can be removed by pressing
while on a +line with a breakpoint or by creating a visual selection of the breakpoints and +deleting them at once with . + ------------------------------------------------------------------------------ 4.5 Evaluating code *VdebugEval* diff --git a/python3/vdebug/debugger_interface.py b/python3/vdebug/debugger_interface.py index 45212105..19a85830 100644 --- a/python3/vdebug/debugger_interface.py +++ b/python3/vdebug/debugger_interface.py @@ -82,7 +82,10 @@ def handle_delete_line_keypress(self): def handle_delete_visual_keypress(self): """React to a vunmap keypress event. """ - return self.event_dispatcher.delete_visual(self.session_handler) + return self.event_dispatcher.event_visual( + self.session_handler, + 'delete' + ) def handle_double_click(self): """React to a mouse double click event. diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 8bf09bc8..a07bb3c3 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -446,18 +446,28 @@ def run(self, args): # If in the breakpoint window, toggle breakpoint instead of adding/deleting one window_name = Dispatcher._get_window_name() if window_name == self.session_handler.ui().windows.breakpoints().name: - lineno = vim.current.window.cursor[0] - line = self.session_handler.ui().windows.breakpoints().line_at(lineno - 1) - id = Dispatcher._get_breakpoint_id_breakpoint_window(line) - if not id: - log.Log("No breakpoint founr at current cursor position", - log.Logger.DEBUG) - return + buf = vim.current.buffer + try: + (lnum1, col1) = buf.mark('<') + (lnum2, col2) = buf.mark('>') + lines = vim.eval('getline({}, {})'.format(lnum1, lnum2)) - self.session_handler.dispatch_event("toggle_breakpoint", "{} {}".format(id, "toggle")) + # The visual marks do not unset automatically + vim.command(':delmarks <>') + except TypeError: + lineno = vim.current.window.cursor[0] + lines = [self.session_handler.ui().windows.breakpoints().line_at(lineno - 1)] - return + for line in lines: + id = Dispatcher._get_breakpoint_id_breakpoint_window(line) + if not id: + log.Log("No breakpoint founr at current cursor position", + log.Logger.DEBUG) + continue + self.session_handler.dispatch_event("toggle_breakpoint", "{} {}".format(id, "toggle")) + + return bp = breakpoint.Breakpoint.parse(self.ui, args) if bp.type == "line": @@ -806,7 +816,7 @@ def delete_line(self, session): RemoveBreakpointEvent(session).run(id) - def delete_visual(self, session): + def event_visual(self, session, event): window_name = self._get_window_name() if window_name == session.ui().windows.breakpoints().name: @@ -819,11 +829,12 @@ def delete_visual(self, session): for line in lines: id = self._get_breakpoint_id_breakpoint_window(line) if not id: - log.Log("No breakpoint founr at current cursor position", + log.Log("No breakpoint found at current cursor position", log.Logger.DEBUG) return False - RemoveBreakpointEvent(session).run(id) + if event == 'delete': + RemoveBreakpointEvent(session).run(id) @staticmethod def _get_event_by_position(session): From a8c2e295248bdf1106f07667be544331fe4ee8fc Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Sat, 9 May 2020 10:49:14 +0200 Subject: [PATCH 19/47] Close quietly when exiting vim This will stop showning "Vdebug is not running" when quiting vim. If Vdebug was running it will just silently close it so we can properly exit vim. Signed-off-by: BlackEagle --- plugin/vdebug.vim | 2 +- python3/vdebug/debugger_interface.py | 5 +++++ python3/vdebug/session.py | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index b240fc8f..fc5dce81 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -324,7 +324,7 @@ endfunction augroup Vdebug augroup END augroup VdebugOut -autocmd VimLeavePre * python3 debugger.close() +autocmd VimLeavePre * python3 debugger.quit() augroup END call Vdebug_load_options(g:vdebug_options) diff --git a/python3/vdebug/debugger_interface.py b/python3/vdebug/debugger_interface.py index 19a85830..9aa3f8ac 100644 --- a/python3/vdebug/debugger_interface.py +++ b/python3/vdebug/debugger_interface.py @@ -179,3 +179,8 @@ def close(self): """Close the connection, or the UI if already closed. """ self.session_handler.stop() + + def quit(self): + """Close the connection, or the UI if already closed. On Exit + """ + self.session_handler.stop(quiet=True) diff --git a/python3/vdebug/session.py b/python3/vdebug/session.py index 893b8d69..a23d6eac 100644 --- a/python3/vdebug/session.py +++ b/python3/vdebug/session.py @@ -64,7 +64,7 @@ def run(self): else: self.listen() - def stop(self): + def stop(self, quiet=False): if self.is_connected(): self.__session.close_connection() elif self.is_listening(): @@ -72,7 +72,8 @@ def stop(self): elif self.is_open(): self.__ui.close() else: - self.__ui.say("Vdebug is not running") + if False is quiet: + self.__ui.say("Vdebug is not running") def close(self): self.stop_listening() From 85e81ec1f55308ecb7b96de51ff16404f3aa9be1 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Tue, 9 Jun 2020 16:03:50 +0200 Subject: [PATCH 20/47] Documentation: warn about using links in path maps --- doc/Vdebug.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 9e0a6fef..716eb2d9 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -1161,6 +1161,11 @@ direction. It is possible to have multiple file path mappings by adding more items in the "path_maps" dictionary. +Be careful when you use symlinked paths. Resolving the local path may be +needed before adding to the "path_maps" dictionary (see |resolve()| for example). +The remote log may be helpful to inspect the paths that are present +in requests and responses. + ------------------------------------------------------------------------------ 9.2 Connecting the two machines *VdebugRemoteConnection* From 40b383cd0ae35906bdb9b3ecbfcbc732488d75e7 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Tue, 9 Jun 2020 16:07:21 +0200 Subject: [PATCH 21/47] fixup! Documentation: warn about using links in path maps --- doc/Vdebug.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 716eb2d9..384bd2be 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -1163,7 +1163,7 @@ It is possible to have multiple file path mappings by adding more items in the Be careful when you use symlinked paths. Resolving the local path may be needed before adding to the "path_maps" dictionary (see |resolve()| for example). -The remote log may be helpful to inspect the paths that are present +The remote log of the debugger may be helpful to inspect the paths that are present in requests and responses. ------------------------------------------------------------------------------ From 609d88c3ed020d8c96d6c85a220d6edfebf73c48 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Tue, 9 Jun 2020 17:40:16 +0200 Subject: [PATCH 22/47] Add info about logging communication by VDebug --- doc/Vdebug.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 384bd2be..3c17fcc0 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -1163,7 +1163,8 @@ It is possible to have multiple file path mappings by adding more items in the Be careful when you use symlinked paths. Resolving the local path may be needed before adding to the "path_maps" dictionary (see |resolve()| for example). -The remote log of the debugger may be helpful to inspect the paths that are present +The remote log of the debugger (or the local, see |VdebugOptions-debug_window_level| +or |VdebugOptions-debug_file_level|) may be helpful to inspect the paths that are present in requests and responses. ------------------------------------------------------------------------------ From 97e637cacd166839c975ba5a9485c549cc180540 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Sun, 21 Jun 2020 01:55:15 +0200 Subject: [PATCH 23/47] Highlight the current stack position on DebuggerStack and SourceWindow --- plugin/vdebug.vim | 9 +++++++++ python3/vdebug/event.py | 2 ++ python3/vdebug/ui/vimui.py | 11 +++++++++++ 3 files changed, 22 insertions(+) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index fc5dce81..67a5fa9f 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -90,6 +90,7 @@ let g:vdebug_options_defaults = { \ 'marker_open_tree' : '▾', \ 'sign_breakpoint' : '▷', \ 'sign_current' : '▶', +\ 'sign_current_stack_position' : '▶', \ 'sign_disabled': '▌▌', \ 'continuous_mode' : 1, \ 'background_listener' : 1, @@ -105,6 +106,7 @@ if g:vdebug_force_ascii == 1 let g:vdebug_options_defaults['marker_open_tree'] = '-' let g:vdebug_options_defaults['sign_breakpoint'] = 'B>' let g:vdebug_options_defaults['sign_current'] = '->' + let g:vdebug_options_defaults['sign_current_stack_position'] = '->' let g:vdebug_options_defaults['sign_disabled'] = 'B|' endif @@ -145,12 +147,19 @@ endif if hlexists('DbgDisabledSign') == 0 highlight DbgDisabledSign term=reverse ctermbg=White ctermfg=Cyan guibg=#b4ee9a guifg=#888888 endif +if hlexists('DbgCurrentStackPositionSign') == 0 + highlight DbgCurrentStackPositionSign term=reverse ctermbg=White ctermfg=Cyan guibg=#e17e67 guifg=#888888 +endif +if hlexists('DbgCurrentStackPositionLine') == 0 + highlight DbgCurrentStackPositionLine term=reverse ctermbg=White ctermfg=Cyan guibg=#e17e67 guifg=#888888 +endif " Signs and highlighted lines for breakpoints, etc. function! s:DefineSigns() exe 'sign define breakpt text=' . g:vdebug_options['sign_breakpoint'] . ' texthl=DbgBreakptSign linehl=DbgBreakptLine' exe 'sign define current text=' . g:vdebug_options['sign_current'] . ' texthl=DbgCurrentSign linehl=DbgCurrentLine' exe 'sign define breakpt_dis text=' . g:vdebug_options['sign_disabled'] . ' texthl=DbgDisabledSign linehl=DbgDisabledLine' + exe 'sign define current_stack_position text=' . g:vdebug_options['sign_current_stack_position'] . ' texthl=DbgCurrentStackPositionSign linehl=DbgCurrentStackPositionLine' endfunction function! s:BreakpointTypes(A,L,P) diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index a07bb3c3..b43a63f5 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -116,6 +116,7 @@ def run(self): line = self.ui.windows.stack().line_at(lineno - 1) if line.find(" @ ") == -1: return False + self.ui.windows.stack().place_pointer(lineno) stack_number_startpos = line.find("[") + 1 stack_number_endpos = line[stack_number_startpos:].rfind("]") + 1 @@ -128,6 +129,7 @@ def run(self): lineno = file_and_line[line_pos+1:] self.ui.sourcewin.set_file(file) self.ui.sourcewin.set_line(lineno) + self.ui.sourcewin.place_pointer(lineno) self.dispatch("change_stack", stack_number) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index a87a64c6..be6a98ed 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -698,6 +698,8 @@ class StackWindow(Window): name = "DebuggerStack" + pointer_sign_id = '6147' + def on_create(self): self.command('inoremap ' ':python3 debugger.handle_return_keypress()') @@ -710,6 +712,15 @@ def on_create(self): def write(self, msg, return_focus=True): Window.write(self, msg, after="normal gg") + def place_pointer(self, line): + log.Log("Stack window: placing pointer sign on line "+str(line), log.Logger.INFO) + self.remove_pointer() + vim.command('sign place %s name=current_stack_position priority=99 line=%s' + % (self.pointer_sign_id, line)) + + def remove_pointer(self): + vim.command('sign unplace %s' % self.pointer_sign_id) + class WatchWindow(Window): From 1ebcbed5c9950a4004b76cb7346684e0e611e12f Mon Sep 17 00:00:00 2001 From: alfredbez Date: Thu, 16 Jul 2020 13:26:39 +0200 Subject: [PATCH 24/47] Handle TypeError in event.py --- python3/vdebug/event.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index b43a63f5..7e4acb3a 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -274,7 +274,10 @@ class RefreshEvent(Event): def run(self, status): - status_str = str(status) + try: + status_str = str(status) + except TypeError: + return if not status_str: return From c7a2a7231bc7aec0b33b35e8d080bcd3e1baf8ab Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Tue, 18 Aug 2020 11:56:00 +0200 Subject: [PATCH 25/47] only use sign priority in supported versions check if vim > 8.1 or neovim is > 0.4.0 before using priority on signs. Fixes #470 Signed-off-by: BlackEagle --- python3/vdebug/ui/vimui.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index be6a98ed..38cdf119 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -351,6 +351,8 @@ class SourceWindow(interface.Window): file = None pointer_sign_id = '6145' breakpoint_sign_id = '6146' + has_sign_priority = vim.vvars['version'] > 801 \ + or vim.funcs.has('nvim-0-4-0') def focus(self): vim.command("1wincmd w") @@ -388,8 +390,10 @@ def get_file(self): def place_pointer(self, line): log.Log("Placing pointer sign on line "+str(line), log.Logger.INFO) self.remove_pointer() - vim.command('sign place %s name=current priority=99 line=%s file=%s' - % (self.pointer_sign_id, line, self.file)) + signstr = 'sign place %s name=current line=%s file=%s' + if self.has_sign_priority: + signstr = 'sign place %s name=current priority=99 line=%s file=%s' + vim.command(signstr % (self.pointer_sign_id, line, self.file)) def remove_pointer(self): vim.command('sign unplace %s' % self.pointer_sign_id) @@ -699,6 +703,8 @@ class StackWindow(Window): name = "DebuggerStack" pointer_sign_id = '6147' + has_sign_priority = vim.vvars['version'] > 801 \ + or vim.funcs.has('nvim-0-4-0') def on_create(self): self.command('inoremap ' @@ -715,8 +721,11 @@ def write(self, msg, return_focus=True): def place_pointer(self, line): log.Log("Stack window: placing pointer sign on line "+str(line), log.Logger.INFO) self.remove_pointer() - vim.command('sign place %s name=current_stack_position priority=99 line=%s' - % (self.pointer_sign_id, line)) + signstr = 'sign place %s name=current_stack_position line=%s' + if self.has_sign_priority: + signstr = \ + 'sign place %s name=current_stack_position priority=99 line=%s' + vim.command(signstr % (self.pointer_sign_id, line)) def remove_pointer(self): vim.command('sign unplace %s' % self.pointer_sign_id) From 58c457e9a6869eaad274225e11e7afd0e3797ff9 Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Tue, 18 Aug 2020 17:03:12 +0200 Subject: [PATCH 26/47] only neovim has vim.funcs when checking if we can use sign priority we must make sure to check if vim.funcs exists before using it because its only available in neovim. You don't see this issue poping up if your version of vim is recent enough since it will not contine into the or. Fixes #474 Signed-off-by: BlackEagle --- python3/vdebug/ui/vimui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 38cdf119..a8e078a2 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -352,7 +352,7 @@ class SourceWindow(interface.Window): pointer_sign_id = '6145' breakpoint_sign_id = '6146' has_sign_priority = vim.vvars['version'] > 801 \ - or vim.funcs.has('nvim-0-4-0') + or (hasattr(vim, 'funcs') and vim.funcs.has('nvim-0-4-0')) def focus(self): vim.command("1wincmd w") @@ -704,7 +704,7 @@ class StackWindow(Window): pointer_sign_id = '6147' has_sign_priority = vim.vvars['version'] > 801 \ - or vim.funcs.has('nvim-0-4-0') + or (hasattr(vim, 'funcs') and vim.funcs.has('nvim-0-4-0')) def on_create(self): self.command('inoremap ' From 74430eaf9eed89a9466ff9230f568491bda574ee Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Tue, 18 Aug 2020 17:26:41 +0200 Subject: [PATCH 27/47] allow to manually force ascii if needed Allow to set g:vdebug_force_ascii in your configuration to allow skipping the use of unicode glyphs. Before this was always set automatically. related #468 Signed-off-by: BlackEagle --- plugin/vdebug.vim | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 67a5fa9f..7c605d5a 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -34,14 +34,16 @@ if !has('python3') finish endif -" Nice characters get screwed up on windows -if has('win32') || has('win64') - let g:vdebug_force_ascii = 1 -elseif has('multi_byte') == 0 - let g:vdebug_force_ascii = 1 -else - let g:vdebug_force_ascii = 0 -end +if !exists('g:vdebug_force_ascii') + " Nice characters get screwed up on windows + if has('win32') || has('win64') + let g:vdebug_force_ascii = 1 + elseif has('multi_byte') == 0 + let g:vdebug_force_ascii = 1 + else + let g:vdebug_force_ascii = 0 + end +endif if !exists('g:vdebug_options') let g:vdebug_options = {} From f3f0bd7fc0b7f19912fc859293ca83024a37cd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 21 Aug 2020 15:06:06 +0200 Subject: [PATCH 28/47] Use a/an when appropriate The rule is "a" when followed by a consonant sound, "an" otherwise. --- doc/Vdebug.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 3c17fcc0..2624ed15 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -194,7 +194,7 @@ able to apply it to your circumstance. The most popular DBGP debugger for PHP is Xdebug. I find that the most effective way to install Xdebug is to use PECL, instead -of a OS-level package manager such as aptitude or yum. You can also compile it +of an OS-level package manager such as aptitude or yum. You can also compile it from source if you're feeling hardy. To install it via PECL, run this from a command line (requires root/admin privileges): > @@ -238,7 +238,7 @@ setting up Xdebug, or you can email me and I'll do my best to help. ------------------------------------------------------------------------------ 3.2 Python set up *VdebugSetUpPython* -Python has an standalone debugging tool that you can use from the command line, +Python has a standalone debugging tool that you can use from the command line, but to use Vdebug in conjunction with your Python scripts you will have to grab the "pydbgp" tool, created by ActiveState (who make the Komodo Edit/IDE software). @@ -283,7 +283,7 @@ Try installing and using it like this: > ------------------------------------------------------------------------------ 3.3 Ruby set up *VdebugSetUpRuby* -Like Python, Ruby has an standalone debugging tool that you can use from the +Like Python, Ruby has a standalone debugging tool that you can use from the command line, but to use Vdebug in conjunction with your Ruby scripts you will have to get the "rdbgp.rb" script that comes bundled with Komodo Edit/IDE by Activestate. @@ -383,7 +383,7 @@ is the port. ------------------------------------------------------------------------------ 3.6 TCL/Wish set up *VdebugSetUpTcl* -Like Python and Ruby, Tcl and Wish have an standalone debugging tool that you +Like Python and Ruby, Tcl and Wish have a standalone debugging tool that you can use from the command line, which has again been made available by ActiveState. From 38345734ee7635733a0412f72e9e33719b59e520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 21 Aug 2020 15:06:51 +0200 Subject: [PATCH 29/47] Invert meaning back to what was intended --- doc/Vdebug.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 2624ed15..e950a75a 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -232,8 +232,8 @@ then use this instead of php when debugging. For instance, instead of "php myscript.php", run "php-xdebug myscript.php" to start the debugger session. You are now officially ready to start debugging with PHP. However, if you've -become unstuck at any point then there are plenty of Google tutorials on -setting up Xdebug, or you can email me and I'll do my best to help. +become stuck at any point then there are plenty of Google tutorials on setting +up Xdebug, or you can email me and I'll do my best to help. ------------------------------------------------------------------------------ 3.2 Python set up *VdebugSetUpPython* From 40691cc3769c8b2d5e911d8ce6b764f408d3b822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 21 Aug 2020 15:07:07 +0200 Subject: [PATCH 30/47] Add an s 3rd person, singular --- doc/Vdebug.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index e950a75a..ce590868 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -325,7 +325,7 @@ If you're still having trouble, drop me an email. Perl is one of the trickier languages to set up, unless you have very specific instructions on what to do. Fortunately, that's what I'm going to give you! -Like Python and Ruby, Activestate provide a standalone module that you can use +Like Python and Ruby, Activestate provides a standalone module that you can use to remotely debug Perl applications. What makes this more difficult than Python and Ruby is that the debugging script changes and, as far as I can see, breaks after a particular version. That means you have to get the right version from From 7cd759a71384e61d37d6a04b51638f8c5886ad49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 21 Aug 2020 15:07:35 +0200 Subject: [PATCH 31/47] Add missing words --- doc/Vdebug.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index ce590868..15dbcd6a 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -1220,7 +1220,7 @@ the question is good I might even add it to this list. the language you're using and that you're doing what's necessary to activate the engine when running the script (e.g. setting environment variables/URL variables). If the problem persists, check that the - debugger engine is connecting the same port and address that Vdebug is + debugger engine is connecting to the same port and address that Vdebug is binding to (the 'port' and 'server' options). The server option is blank by default, which means that it will connect to all available interfaces. Unless you've changed this option, it's unlikely to be the issue. Also @@ -1280,7 +1280,7 @@ the question is good I might even add it to this list. repository and try to implement it yourself! I do accept merges. Q. Why doesn't Ross, the largest friend, simply eat the other ones? - A. Think of the indigestion that would result. + A. Think of the indigestion that would result in. Q. My command line php script seems to stop at the first line, but the source code is not loaded in the debugger window, how can that be? From e86bef5684235b709cc1aa7beb7764c078526ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 21 Aug 2020 16:04:11 +0200 Subject: [PATCH 32/47] Add tip about getcwd() and path maps --- doc/Vdebug.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index 3c17fcc0..4d4ea589 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -1167,6 +1167,15 @@ The remote log of the debugger (or the local, see |VdebugOptions-debug_window_le or |VdebugOptions-debug_file_level|) may be helpful to inspect the paths that are present in requests and responses. +If you happen to be using the same layout for all your remote servers in +different projects, you may map the same remote directory to the root of your +project. For instance, if the root of your project is always /app, and you +always run vim from the root of your projects, you may want to use the +following configuration: > + + let g:vdebug_options.path_maps = {"/app": getcwd() } +< + ------------------------------------------------------------------------------ 9.2 Connecting the two machines *VdebugRemoteConnection* From c711f60a22146cd549ed62603075001a75e0d6c6 Mon Sep 17 00:00:00 2001 From: Mel Dafert Date: Wed, 19 Aug 2020 13:33:54 +0200 Subject: [PATCH 33/47] make BackgroundSocketCreator async using asyncio --- python3/vdebug/connection.py | 51 ++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index a73aa111..6698c7e7 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -4,6 +4,7 @@ import sys import threading import time +import asyncio from . import log @@ -157,11 +158,12 @@ def has_socket(self): class BackgroundSocketCreator(threading.Thread): - def __init__(self, host, port, message_q, output_q): - self.__message_q = message_q + def __init__(self, host, port, output_q): self.__output_q = output_q self.__host = host self.__port = port + self.__socket_task = None + self.__loop = None threading.Thread.__init__(self) @staticmethod @@ -169,19 +171,29 @@ def log(message): log.Log(message, log.Logger.DEBUG) def run(self): + # needed for python 3.5 + self.__loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.__loop) + self.__loop.run_until_complete(self.run_async()) + + async def run_async(self): self.log("Started") self.log("Listening on port %s" % self.__port) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.setblocking(1) + s.setblocking(False) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((self.__host, self.__port)) - s.settimeout(5) # timeout after 5 seconds so we can check messages s.listen(5) while 1: try: - self.__peek_for_exit() - client, address = s.accept() + # using ensure_future here since before 3.7, this is not a coroutine, but returns a future + self.__socket_task = asyncio.ensure_future(self.__loop.sock_accept(s)) + client, address = await self.__socket_task + # set resulting socket to blocking + client.setblocking(True) + client.settimeout(5) + self.log("Found client, %s" % str(address)) self.__output_q.put((client, address)) break @@ -195,7 +207,10 @@ def run(self): if socket_error.errno == errno.EADDRINUSE: self.log("Address already in use") print("Socket is already in use") - except Exception: + except asyncio.CancelledError as e: + self.log("Stopping server") + self.__socket_task = None + except Exception as e: print("Exception caught") self.log("Error: %s" % str(sys.exc_info())) self.log("Stopping server") @@ -203,23 +218,19 @@ def run(self): self.log("Finishing socket server") s.close() - def __peek_for_exit(self): - try: - # self.log("Checking for exit") - self.__check_exit(self.__message_q.get_nowait()) - except queue.Empty: - pass + def _exit(self): + if self.__socket_task: + # this will raise asyncio.CancelledError + self.__socket_task.cancel() - @staticmethod - def __check_exit(message): - if message == "exit": - raise Exception("Exiting") + # called from outside of the thread + def exit(self): + self.__loop.call_soon_threadsafe(self._exit) class SocketServer: def __init__(self): - self.__message_q = queue.Queue(0) self.__socket_q = queue.Queue(1) self.__thread = None @@ -229,7 +240,7 @@ def __del__(self): def start(self, host, port): if not self.is_alive(): self.__thread = BackgroundSocketCreator( - host, port, self.__message_q, self.__socket_q) + host, port, self.__socket_q) self.__thread.start() def is_alive(self): @@ -243,7 +254,7 @@ def socket(self): def stop(self): if self.is_alive(): - self.__message_q.put_nowait("exit") + self.__thread.exit() self.__thread.join(3000) if self.has_socket(): self.socket()[0].close() From e956d9d994066b3843760aa599b8ef973380a2c0 Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Wed, 9 Sep 2020 19:03:19 +0200 Subject: [PATCH 34/47] add default feature set of some features If we look at https://xdebug.org/docs/dbgp#options-and-configuration in the feature names we see any dbgp debugger must provide some feature set by default. Even if that feature is not actually supported. So from now on we will set multiple_sessions = 0 because Vdebug does not support this at the moment and we will try to set extended_properties = 1; if the used debugger does not support it we will silently continue without the feature. fixes #369 Signed-off-by: BlackEagle --- python3/vdebug/connection.py | 2 +- python3/vdebug/session.py | 66 ++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index 6698c7e7..db195856 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -81,7 +81,7 @@ def send_msg(self, cmd): cmd -- command to send """ - #self.sock.send(cmd + '\0') + # self.sock.send(cmd + '\0') MSGLEN = len(cmd) totalsent = 0 while totalsent < MSGLEN: diff --git a/python3/vdebug/session.py b/python3/vdebug/session.py index a23d6eac..a6792bbc 100644 --- a/python3/vdebug/session.py +++ b/python3/vdebug/session.py @@ -37,13 +37,14 @@ def listen(self): print("Waiting for a connection: none found so far") elif self.listener and self.listener.is_ready(): print("Found connection, starting debugger") + log.Log("Got connection, starting", log.Logger.DEBUG) self.__new_session() else: self.start_listener() def start_listener(self): self.listener = listener.Listener.create() - print("Vdebug will wait for a connection in the background") + print("Vdebug will wait for a connection") util.Environment.reload() if self.is_open(): self.ui().set_status("listening") @@ -103,6 +104,7 @@ def start_if_ready(self): try: if self.listener.is_ready(): print("Found connection, starting debugger") + log.Log("Got connection, starting", log.Logger.DEBUG) self.__new_session() return True return False @@ -206,7 +208,9 @@ def start(self, connection): self.__ui.set_conn_details(addr[0], addr[1]) self.__collect_context_names() - self.__set_features() + self.__check_features() # only for debugging at the moment + self.__set_default_features() # features we try by default + self.__set_features() # user defined features self.__initialize_breakpoints() if opts.Options.get('break_on_open', int) == 1: @@ -229,6 +233,64 @@ def detach(self): self.close_connection(False) + def __check_features(self): + must_features = [ + 'language_supports_threads', + 'language_name', + 'language_version', + 'encoding', # has set + 'protocol_version', + 'supports_async', + 'data_encoding', + 'breakpoint_languages', + 'breakpoint_types', + 'resolved_breakpoints', + 'multiple_sessions', # has set + 'max_children', # has set + 'max_data', # has set + 'max_depth', # has set + 'extended_properties', # has set + ] + maybe_features = [ + 'supported_encodings', + 'supports_postmortem', + 'show_hidden', # has set + 'notify_ok', # has set + ] + for feature in must_features: + try: + feature_value = self.__api.feature_get(feature) + log.Log( + "Must Feature: %s = %s" % (feature, str(feature_value)), + log.Logger.DEBUG + ) + except dbgp.DBGPError: + error_str = "Failed to get feature %s" % feature + log.Log(error_str, log.Logger.DEBUG) + + for feature in maybe_features: + try: + feature_value = self.__api.feature_get(feature) + log.Log( + "Maybe Feature: %s = %s" % (feature, str(feature_value)), + log.Logger.DEBUG + ) + except dbgp.DBGPError: + error_str = "Failed to get feature %s" % feature + log.Log(error_str, log.Logger.DEBUG) + + def __set_default_features(self): + features = { + 'multiple_sessions': 0, # explicitly disable multiple sessions atm + 'extended_properties': 1, + } + for name, value in features.items(): + try: + self.__api.feature_set(name, value) + except dbgp.DBGPError as e: + error_str = "Failed to set feature %s: %s" % (name, e.args[0]) + log.Log(error_str, log.Logger.DEBUG) + def __set_features(self): """Evaluate vim dictionary of features and pass to debugger. From b550088818271b6ceb879bab300b64270cdc5b6e Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Wed, 9 Sep 2020 20:57:48 +0200 Subject: [PATCH 35/47] vimui linting style fix Signed-off-by: BlackEagle --- python3/vdebug/ui/vimui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index a8e078a2..478c4fe9 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -158,8 +158,8 @@ def __init__(self): 'DebuggerStatus': 'vertical leftabove new' }, 'window_size': { - 'DebuggerWatch': { 'height' : 15 }, - 'DebuggerStatus': { 'height' : 1 } + 'DebuggerWatch': {'height': 15}, + 'DebuggerStatus': {'height': 1} }, 'window_arrangement': [ 'DebuggerWatch', From 8ea3620d8024abe0bcb7a814e3c2d1fe23ee12de Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Wed, 9 Sep 2020 20:58:16 +0200 Subject: [PATCH 36/47] no need to load the buffer, we already have it Signed-off-by: BlackEagle --- python3/vdebug/ui/vimui.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 478c4fe9..47de27e6 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -597,7 +597,6 @@ def destroy(self, wipeout=True): if self._buffer is None: return self.is_open = False - self._buffer = HiddenBuffer(self._buffer.contents()) if wipeout and int(vim.eval('buffer_exists("%s")' % self.name)) == 1: vim.command('bwipeout %s' % self.name) self.on_destroy() From 9096fc157bea32d3c3cdce9b3808a7cb3dcad329 Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Wed, 9 Sep 2020 20:58:48 +0200 Subject: [PATCH 37/47] fix BufWinLeave for the main Vdebug windows Avoids trace: ``` Error detected while processing BufWinLeave Autocommands for "DebuggerBreakpoints": Traceback (most recent call last): File "", line 1, in File "/home/user/.vim/pack/bundle/opt/vdebug/python3/vdebug/debugger_interface.py", line 114, in mark_window_as_closed self.session_handler.ui().mark_window_as_closed(window) File "/home/user/.vim/pack/bundle/opt/vdebug/python3/vdebug/ui/vimui.py", line 173, in mark_window_as_closed self.windows.window(name).mark_as_closed() File "/home/user/.vim/pack/bundle/opt/vdebug/python3/vdebug/ui/vimui.py", line 533, in mark_as_closed self.destroy() File "/home/user/.vim/pack/bundle/opt/vdebug/python3/vdebug/ui/vimui.py", line 598, in destroy vim.command('bwipeout %s' % self.name) vim.error: Vim(bwipeout):E937: Attempt to delete a buffer that is in use: DebuggerBreakpoints ``` fixes: #451 Signed-off-by: BlackEagle --- python3/vdebug/ui/vimui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 47de27e6..641f3972 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -586,7 +586,8 @@ def create(self, open_cmd): self.creation_count += 1 if self.creation_count == 1: - cmd = 'autocmd Vdebug BufWinLeave %s' % self.name + cmd = 'autocmd Vdebug BufWinLeave %s silent! bdelete %s' \ + % (self.name, self.name) cmd += ' python3 debugger.mark_window_as_closed("%s")' % self.name vim.command(cmd) From 1f3ba272bb7533c21c3f76bbf08961a7bf431ef4 Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Sat, 26 Sep 2020 19:18:09 +0200 Subject: [PATCH 38/47] Revert "no need to load the buffer, we already have it" This reverts commit 8ea3620d8024abe0bcb7a814e3c2d1fe23ee12de. Fixes #485 #486 #487 --- python3/vdebug/ui/vimui.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/vdebug/ui/vimui.py b/python3/vdebug/ui/vimui.py index 641f3972..5f46ba66 100644 --- a/python3/vdebug/ui/vimui.py +++ b/python3/vdebug/ui/vimui.py @@ -598,6 +598,7 @@ def destroy(self, wipeout=True): if self._buffer is None: return self.is_open = False + self._buffer = HiddenBuffer(self._buffer.contents()) if wipeout and int(vim.eval('buffer_exists("%s")' % self.name)) == 1: vim.command('bwipeout %s' % self.name) self.on_destroy() From d54b80e6699f6eaea1c93d5a63939e4d398f127d Mon Sep 17 00:00:00 2001 From: BlackEagle Date: Tue, 29 Sep 2020 12:18:44 +0200 Subject: [PATCH 39/47] we should not just timeout when there is a debugging session move the client.settimeout back to the socket fixes #484 Signed-off-by: BlackEagle --- python3/vdebug/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index db195856..bded91d9 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -185,6 +185,7 @@ async def run_async(self): s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((self.__host, self.__port)) s.listen(5) + s.settimeout(5) while 1: try: # using ensure_future here since before 3.7, this is not a coroutine, but returns a future @@ -192,7 +193,6 @@ async def run_async(self): client, address = await self.__socket_task # set resulting socket to blocking client.setblocking(True) - client.settimeout(5) self.log("Found client, %s" % str(address)) self.__output_q.put((client, address)) From ec999953066d8f40168d5eb7382a1004c5612161 Mon Sep 17 00:00:00 2001 From: David Tourrel Date: Wed, 7 Oct 2020 09:36:16 +0200 Subject: [PATCH 40/47] Avoid vim to hang on debugger close ref #490 --- python3/vdebug/connection.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index bded91d9..89b34dad 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -185,7 +185,6 @@ async def run_async(self): s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((self.__host, self.__port)) s.listen(5) - s.settimeout(5) while 1: try: # using ensure_future here since before 3.7, this is not a coroutine, but returns a future From ba8a23bb08c5293326290275ed55f8c7e0517c31 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Wed, 30 Dec 2020 16:26:55 +1100 Subject: [PATCH 41/47] docs: fix simple typo, detatch -> detach There is a small typo in tests/test_dbgp_api.py. Should read `detach` rather than `detatch`. --- tests/test_dbgp_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_dbgp_api.py b/tests/test_dbgp_api.py index 26382d57..4e998059 100644 --- a/tests/test_dbgp_api.py +++ b/tests/test_dbgp_api.py @@ -127,10 +127,10 @@ def test_stop_retval(self): assert str(status_res) == "stopping" def test_detatch_retval(self): - """Test that the detatch command receives a message from the api.""" + """Test that the detach command receives a message from the api.""" self.p.conn.recv_msg.return_value = """\n - Date: Tue, 31 Aug 2021 13:36:21 +0200 Subject: [PATCH 42/47] Added Xdebug v3 instructions to helpfile --- doc/Vdebug.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index f7f30f0a..e0be1b58 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -206,7 +206,7 @@ it as a zend extension. This can be done in the PHP INI file, but in Ubuntu I can add a new file to /etc/php5/conf.d/ that contains all the configuration options and gets loaded automatically by PHP. -Add these options to the INI file: > +For Xdebug v2, add these options to the INI file: > zend_extension=/path/to/xdebug.so xdebug.remote_enable=on @@ -214,6 +214,16 @@ Add these options to the INI file: > xdebug.remote_host=localhost xdebug.remote_port=9000 < + +For Xdebug v3, add tese options to the INI file: > + + zend_extension=/path/to/xdebug.so + xdebug.mode=debug + xdebug.client_host=localhost + xdebug.client_port=9000 +< +Please refer to https://xdebug.org/docs/upgrade_guide for instructions on how to upgrade from v2 to v3. + If using Apache, restart it to enable the new library. The command line interface should be ready to go - type "php -v" and you should see the line > with Xdebug v2.2.0, Copyright (c) 2002-2012, by Derick Rethans From 21dbc4d93ea397d7369f96dccf5da8cfa999a75f Mon Sep 17 00:00:00 2001 From: Aleix Quintana Date: Wed, 17 Nov 2021 21:50:51 +0100 Subject: [PATCH 43/47] Add dbgpproxy support --- plugin/vdebug.vim | 2 + python3/vdebug/connection.py | 101 ++++++++++++++++++++++++++++++++--- python3/vdebug/listener.py | 8 ++- 3 files changed, 104 insertions(+), 7 deletions(-) diff --git a/plugin/vdebug.vim b/plugin/vdebug.vim index 7c605d5a..216fe681 100644 --- a/plugin/vdebug.vim +++ b/plugin/vdebug.vim @@ -79,6 +79,8 @@ let g:vdebug_options_defaults = { \ 'port' : 9000, \ 'timeout' : 20, \ 'server' : '', +\ "proxy_host" : '', +\ "proxy_port" : 9001, \ 'on_close' : 'stop', \ 'break_on_open' : 1, \ 'ide_key' : '', diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index 89b34dad..d5ce6f4f 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -5,6 +5,7 @@ import threading import time import asyncio +import xml.etree.ElementTree as ET from . import log @@ -103,13 +104,17 @@ def __init__(self, input_stream=None): """ self.__sock = None self.input_stream = input_stream + self.proxy_success = False - def start(self, host='', port=9000, timeout=30): + def start(self, host='', proxy_host = '', proxy_port = 9001, idekey = None, port=9000, timeout=30): """Listen for a connection from the debugger. Listening for the actual connection is handled by self.listen() host -- host name where debugger is running (default '') port -- port number which debugger is listening on (default 9000) + proxy_host -- If using a DBGp Proxy, host name where the proxy is running (default None to disable) + proxy_port -- If using a DBGp Proxy, port where the proxy is listening for debugger connections (default 9001) + idekey -- The idekey that our Api() wrapper is expecting. Only required if using a proxy timeout -- time in seconds to wait for a debugger connection before giving up (default 30) """ print('Waiting for a connection (Ctrl-C to cancel, this message will ' @@ -120,13 +125,18 @@ def start(self, host='', port=9000, timeout=30): serv.setblocking(1) serv.bind((host, port)) serv.listen(5) - self.__sock = self.listen(serv, timeout) + if proxy_host and proxy_port: + # Register ourselves with the proxy server + self.proxyinit(proxy_host, proxy_port, port, idekey) + self.__sock = self.accept(serv, timeout) except socket.timeout: + self.proxystop() raise TimeoutError("Timeout waiting for connection") finally: + self.proxystop(proxy_host, proxy_port, idekey) serv.close() - def listen(self, serv, timeout): + def accept(self, serv, timeout): """Non-blocking listener. Provides support for keyboard interrupts from the user. Although it's non-blocking, the user interface will still block until the timeout is reached. @@ -155,13 +165,50 @@ def socket(self): def has_socket(self): return self.__sock is not None + def proxyinit(self, proxy_host, proxy_port, port, idekey): + """Register ourselves with the proxy.""" + if not proxy_host or not proxy_port: + return + + self.log("Connecting to DBGp proxy [%s:%d]" % (proxy_host, proxy_port)) + proxy_conn = socket.create_connection((proxy_host, proxy_port), 30) + + self.log("Sending proxyinit command") + msg = 'proxyinit -p %d -k %s -m 0' % (port, idekey) + proxy_conn.send(msg.encode()) + proxy_conn.shutdown(socket.SHUT_WR) + + # Parse proxy response + response = proxy_conn.recv(8192) + proxy_conn.close() + response = ET.fromstring(response) + self.proxy_success = bool(response.get("success")) + + def proxystop(self, proxy_host, proxy_port, idekey): + """De-register ourselves from the proxy.""" + if not self.proxy_success: + return + + proxy_conn = socket.create_connection((proxy_host, proxy_port), 30) + + self.log("Sending proxystop command") + msg = 'proxystop -k %s' % str(idekey) + proxy_conn.send(msg.encode()) + proxy_conn.close() + self.proxy_success = False + + class BackgroundSocketCreator(threading.Thread): - def __init__(self, host, port, output_q): + def __init__(self, host, port, proxy_host, proxy_port, idekey, output_q): self.__output_q = output_q self.__host = host self.__port = port + self.__proxy_host = proxy_host + self.__proxy_port = proxy_port + self.__idekey = idekey + self.proxy_success = False self.__socket_task = None self.__loop = None threading.Thread.__init__(self) @@ -189,6 +236,9 @@ async def run_async(self): try: # using ensure_future here since before 3.7, this is not a coroutine, but returns a future self.__socket_task = asyncio.ensure_future(self.__loop.sock_accept(s)) + if self.__proxy_host and self.__proxy_port: + # Register ourselves with the proxy server + await self.proxyinit() client, address = await self.__socket_task # set resulting socket to blocking client.setblocking(True) @@ -197,9 +247,11 @@ async def run_async(self): self.__output_q.put((client, address)) break except socket.error: + await self.proxystop() # No connection pass except socket.error as socket_error: + await self.proxystop() self.log("Error: %s" % str(sys.exc_info())) self.log("Stopping server") @@ -207,16 +259,53 @@ async def run_async(self): self.log("Address already in use") print("Socket is already in use") except asyncio.CancelledError as e: + await self.proxystop() self.log("Stopping server") self.__socket_task = None except Exception as e: + await self.proxystop() print("Exception caught") self.log("Error: %s" % str(sys.exc_info())) self.log("Stopping server") finally: + await self.proxystop() self.log("Finishing socket server") s.close() + async def proxyinit(self): + """Register ourselves with the proxy.""" + if not self.__proxy_host or not self.__proxy_port: + return + + self.log("Connecting to DBGp proxy [%s:%d]" % (self.__proxy_host, self.__proxy_port)) + proxy_conn = socket.create_connection((self.__proxy_host, self.__proxy_port), 30) + + self.log("Sending proxyinit command") + msg = 'proxyinit -p %d -k %s -m 0' % (self.__port, self.__idekey) + proxy_conn.send(msg.encode()) + proxy_conn.shutdown(socket.SHUT_WR) + + # Parse proxy response + response = proxy_conn.recv(8192) + proxy_conn.close() + response = ET.fromstring(response) + self.proxy_success = bool(response.get("success")) + + async def proxystop(self): + """De-register ourselves from the proxy.""" + if not self.proxy_success: + return + + proxy_conn = socket.create_connection((self.__proxy_host, self.__proxy_port), 30) + + self.log("Sending proxystop command") + msg = 'proxystop -k %s' % str(self.__idekey) + proxy_conn.send(msg.encode()) + proxy_conn.close() + self.proxy_success = False + + + def _exit(self): if self.__socket_task: # this will raise asyncio.CancelledError @@ -236,10 +325,10 @@ def __init__(self): def __del__(self): self.stop() - def start(self, host, port): + def start(self, host, port, proxy_host, proxy_port, ide_key): if not self.is_alive(): self.__thread = BackgroundSocketCreator( - host, port, self.__socket_q) + host, port, proxy_host, proxy_port, ide_key, self.__socket_q) self.__thread.start() def is_alive(self): diff --git a/python3/vdebug/listener.py b/python3/vdebug/listener.py index 15775904..0c39ad2d 100644 --- a/python3/vdebug/listener.py +++ b/python3/vdebug/listener.py @@ -22,6 +22,9 @@ def __init__(self): def start(self): self.__server.start(opts.Options.get('server'), opts.Options.get('port', int), + opts.Options.get('proxy_host'), + opts.Options.get('proxy_port', int), + opts.Options.get('ide_key'), opts.Options.get('timeout', int)) def stop(self): @@ -51,7 +54,10 @@ def start(self): if opts.Options.get("auto_start", int): vim.command('autocmd Vdebug CursorHold,CursorHoldI,CursorMoved,CursorMovedI,FocusGained,FocusLost * python3 debugger.start_if_ready()') self.__server.start(opts.Options.get('server'), - opts.Options.get('port', int)) + opts.Options.get('port', int), + opts.Options.get('proxy_host'), + opts.Options.get('proxy_port', int), + opts.Options.get('ide_key')) def stop(self): if opts.Options.get("auto_start", bool): From 6efc0aefef95ea6abfe06f1053f172b3b4574a1d Mon Sep 17 00:00:00 2001 From: Aleix Quintana Alsius Date: Thu, 18 Nov 2021 11:38:57 +0100 Subject: [PATCH 44/47] Remove unnecessary stops --- python3/vdebug/connection.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/python3/vdebug/connection.py b/python3/vdebug/connection.py index d5ce6f4f..f7494e23 100644 --- a/python3/vdebug/connection.py +++ b/python3/vdebug/connection.py @@ -130,7 +130,6 @@ def start(self, host='', proxy_host = '', proxy_port = 9001, idekey = None, port self.proxyinit(proxy_host, proxy_port, port, idekey) self.__sock = self.accept(serv, timeout) except socket.timeout: - self.proxystop() raise TimeoutError("Timeout waiting for connection") finally: self.proxystop(proxy_host, proxy_port, idekey) @@ -251,7 +250,6 @@ async def run_async(self): # No connection pass except socket.error as socket_error: - await self.proxystop() self.log("Error: %s" % str(sys.exc_info())) self.log("Stopping server") @@ -259,11 +257,9 @@ async def run_async(self): self.log("Address already in use") print("Socket is already in use") except asyncio.CancelledError as e: - await self.proxystop() self.log("Stopping server") self.__socket_task = None except Exception as e: - await self.proxystop() print("Exception caught") self.log("Error: %s" % str(sys.exc_info())) self.log("Stopping server") From 3484f1aa73d26c40bfb6144aec97438009c2fed4 Mon Sep 17 00:00:00 2001 From: Aleix Quintana Alsius Date: Fri, 19 Nov 2021 00:55:10 +0100 Subject: [PATCH 45/47] FeatureGetResponse string cast always return str --- python3/vdebug/dbgp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vdebug/dbgp.py b/python3/vdebug/dbgp.py index b8f1a108..053f0186 100644 --- a/python3/vdebug/dbgp.py +++ b/python3/vdebug/dbgp.py @@ -181,7 +181,7 @@ def is_supported(self): def __str__(self): if self.is_supported(): xml = self.as_xml() - return xml.text + return xml.text if xml.text else "" return "* Feature not supported *" From 617c7e02b219b8e5002c43dda9b9f9ee536a7273 Mon Sep 17 00:00:00 2001 From: BoilingSoup <84747244+BoilingSoup@users.noreply.github.com> Date: Sat, 26 Feb 2022 21:11:24 -0800 Subject: [PATCH 46/47] Update Vdebug.txt --- doc/Vdebug.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Vdebug.txt b/doc/Vdebug.txt index e0be1b58..495d8830 100644 --- a/doc/Vdebug.txt +++ b/doc/Vdebug.txt @@ -215,7 +215,7 @@ For Xdebug v2, add these options to the INI file: > xdebug.remote_port=9000 < -For Xdebug v3, add tese options to the INI file: > +For Xdebug v3, add these options to the INI file: > zend_extension=/path/to/xdebug.so xdebug.mode=debug From 66517871178779ac54e19ed0f34d66805b820664 Mon Sep 17 00:00:00 2001 From: Lucas Hoffmann Date: Thu, 2 May 2024 22:20:58 +0200 Subject: [PATCH 47/47] Fix python syntax warning This fixes #524. --- python3/vdebug/event.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python3/vdebug/event.py b/python3/vdebug/event.py index 7e4acb3a..87842e4c 100644 --- a/python3/vdebug/event.py +++ b/python3/vdebug/event.py @@ -44,16 +44,16 @@ class CursorEvalEvent(Event): """Evaluate the variable currently under the cursor. """ char_regex = { - "default": "a-zA-Z0-9_.\[\]'\"", - "ruby": "$@a-zA-Z0-9_.\[\]'\"", + "default": "a-zA-Z0-9_.\\[\\]'\"", + "ruby": "$@a-zA-Z0-9_.\\[\\]'\"", "perl": "$a-zA-Z0-9_{}'\"", - "php": "$@%a-zA-Z0-9_\[\]'\"\->" + "php": "$@%a-zA-Z0-9_\\[\\]'\">-" } var_regex = { "default": "^[a-zA-Z_]", "ruby": "^[$@a-zA-Z_]", - "php": "^[\$A-Z]", + "php": r"^[\$A-Z]", "perl": "^[$@%]" } @@ -559,7 +559,7 @@ def run(self): line = self.ui.windows.breakpoints().line_at(lineno - 1) # Match on ID - id = re.findall('^[\s][0-9]*[\s]', line) + id = re.findall('^[\\s][0-9]*[\\s]', line) if not id: return False @@ -877,9 +877,9 @@ def _get_window_name(): @staticmethod def _get_breakpoint_id_breakpoint_window(line): # Match on ID - id = re.findall('^[\s][0-9]*[\s]', line) + id = re.findall(r'^[\s][0-9]*[\s]', line) if not id: - log.Log("No breakpoint founr at current cursor position", + log.Log("No breakpoint found at current cursor position", log.Logger.DEBUG) return False