From: oltolm Date: Fri, 28 Feb 2025 18:57:39 +0000 (+0100) Subject: gdb/dap - Add CompletionsRequest X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9882e2bca746acb186cfae8e67d30d91dc211647;p=thirdparty%2Fbinutils-gdb.git gdb/dap - Add CompletionsRequest Use GDB/MI command "-complete" to implement. Co-authored-by: Simon Farre Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31140 Approved-By: Tom Tromey Reviewed-By: Eli Zaretskii --- diff --git a/gdb/NEWS b/gdb/NEWS index 40b0bcf7248..6a557bb4af9 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,10 @@ *** Changes since GDB 16 +* Debugger Adapter Protocol changes + + ** GDB now supports the "completions" request. + * "set style" commands now supports numeric format for basic colors from 0 to 255 and #RRGGBB format for TrueColor. diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in index 287dc7ff739..c08a68d16dd 100644 --- a/gdb/data-directory/Makefile.in +++ b/gdb/data-directory/Makefile.in @@ -97,6 +97,7 @@ PYTHON_FILE_LIST = \ gdb/command/xmethods.py \ gdb/dap/breakpoint.py \ gdb/dap/bt.py \ + gdb/dap/completions.py \ gdb/dap/disassemble.py \ gdb/dap/evaluate.py \ gdb/dap/events.py \ diff --git a/gdb/python/lib/gdb/dap/__init__.py b/gdb/python/lib/gdb/dap/__init__.py index 145aeb611fc..08ca33f5f63 100644 --- a/gdb/python/lib/gdb/dap/__init__.py +++ b/gdb/python/lib/gdb/dap/__init__.py @@ -26,6 +26,7 @@ from . import startup # server object. "F401" is the flake8 "imported but unused" code. from . import breakpoint # noqa: F401 from . import bt # noqa: F401 +from . import completions # noqa: F401 from . import disassemble # noqa: F401 from . import evaluate # noqa: F401 from . import launch # noqa: F401 diff --git a/gdb/python/lib/gdb/dap/completions.py b/gdb/python/lib/gdb/dap/completions.py new file mode 100644 index 00000000000..85acc43dc8e --- /dev/null +++ b/gdb/python/lib/gdb/dap/completions.py @@ -0,0 +1,60 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from typing import Optional + +from .frames import select_frame +from .server import capability, import_column, import_line, request +from .startup import exec_mi_and_log + + +@request("completions") +@capability("supportsCompletionsRequest") +@capability("completionTriggerCharacters", [" ", "."]) +def completions( + *, + frameId: Optional[int] = None, + text: str, + column: int, + line: Optional[int] = None, + **extra, +): + if frameId is not None: + select_frame(frameId) + + column = import_column(column) + if line is None: + line = 1 + else: + line = import_line(line) + text = text.splitlines()[line - 1] + text = text[: column - 1] + mi_result = exec_mi_and_log("-complete", text) + result = [] + completion = None + if "completion" in mi_result: + completion = mi_result["completion"] + result.append({"label": completion, "length": len(completion)}) + # If `-complete' finds one match then `completion' and `matches' + # will contain the same one match. + if ( + completion is not None + and len(mi_result["matches"]) == 1 + and completion == mi_result["matches"][0] + ): + return {"targets": result} + for match in mi_result["matches"]: + result.append({"label": match, "length": len(match)}) + return {"targets": result} diff --git a/gdb/python/lib/gdb/dap/server.py b/gdb/python/lib/gdb/dap/server.py index 8fdf0299d51..7139c798af0 100644 --- a/gdb/python/lib/gdb/dap/server.py +++ b/gdb/python/lib/gdb/dap/server.py @@ -49,6 +49,7 @@ _server = None # This is set by the initialize request and is used when rewriting # line numbers. _lines_start_at_1 = False +_columns_start_at_1 = False class DeferredRequest: @@ -593,6 +594,8 @@ def initialize(**args): _server.send_event_later("initialized") global _lines_start_at_1 _lines_start_at_1 = client_bool_capability("linesStartAt1", True) + global _columns_start_at_1 + _columns_start_at_1 = client_bool_capability("columnsStartAt1", True) return _capabilities.copy() @@ -698,7 +701,7 @@ def send_gdb_with_response(fn): return val -def export_line(line): +def export_line(line: int) -> int: """Rewrite LINE according to client capability. This applies the linesStartAt1 capability as needed, when sending a line number from gdb to the client.""" @@ -710,7 +713,7 @@ def export_line(line): return line -def import_line(line): +def import_line(line: int) -> int: """Rewrite LINE according to client capability. This applies the linesStartAt1 capability as needed, when the client sends a line number to gdb.""" @@ -720,3 +723,17 @@ def import_line(line): # the client starts at 0. line = line + 1 return line + + +def export_column(column: int) -> int: + """Rewrite COLUMN according to client capability. + This applies the columnsStartAt1 capability as needed, + when sending a column number from gdb to the client.""" + return column if _columns_start_at_1 else column - 1 + + +def import_column(column: int) -> int: + """Rewrite COLUMN according to client capability. + This applies the columnsStartAt1 capability as needed, + when the client sends a column number to gdb.""" + return column if _columns_start_at_1 else column + 1