diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8a1b3a6..87157140 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Release Notes
+# 1.11.0
+
+### New
+- Updated bundled LLDB to v19.1.0.
+- The Python module implementing the CodeLLDB Python API is now called `codelldb` (aliased to `debugger` for backward
+ compatibility).
+- Python scripts running in the context of CodeLLDB can now read workspace configuration settings stored under
+ the `lldb.script` namespace via `codelldb.get_config()`.
+
+### Changed
+- To reduce the maintenance burden, support for the Rust language service and custom data formatters in CodeLLDB has
+ been removed. The constant breaking changes in LLDB's language service API, along with Rust's evolving internal
+ representation of `std::` types, have made it increasingly difficult to maintain these updates. Future versions of
+ CodeLLDB will be based on stock LLDB, without the Rust language service. Rust data types will still have partial
+ support via the data formatters provided by `rustc`, but custom formatters will no longer be maintained.
+
# 1.10.0
## New
@@ -14,12 +30,12 @@
# 1.9.2
## New
-- Implemented [Excluded Callers](MANUAL.md#excluded-callers) feature, similar to the [one in Javascript debugger](https://code.visualstudio.com/updates/v1_64#_javascript-debugging).
+- Implemented [Excluded Callers](MANUAL.md#excluded-callers) feature, similar to the
+ [one in Javascript debugger](https://code.visualstudio.com/updates/v1_64#_javascript-debugging).
- Added [create_webview()](MANUAL.md#webview) Python API, which allows scripts to create and manipulate VSCode Webviews.
-This function supersedes functionality of the older `display_html` API.
+ This function supersedes functionality of the older `display_html` API.
- Enabled conditions on exception breakpoints.
-
# 1.9.1
## New
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bfa58cf2..79729e87 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(CodeLLDB)
enable_testing()
-set(VERSION "1.10.1") # Base version
+set(VERSION "1.11.0") # Base version
include(cmake/CopyFiles.cmake)
diff --git a/Cargo.toml b/Cargo.toml
index c9ba5104..bdab307a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,6 +6,7 @@ members = [
"adapter/lldb-stub",
"debuggee/rust",
]
+resolver = "1"
[profile.release]
debug = true
diff --git a/MANUAL.md b/MANUAL.md
index bc41fc95..e77374a2 100644
--- a/MANUAL.md
+++ b/MANUAL.md
@@ -38,7 +38,7 @@
# Starting a New Debug Session
-To start a debugging session you will need to create a [launch configuration](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations) for your program. Here's a minimal one:
+To start a debugging session, you will need to create a [launch configuration](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations) for your program. Here's a minimal one:
```javascript
{
@@ -60,7 +60,7 @@ To start a debugging session you will need to create a [launch configuration](ht
|**initCommands** |[string]| LLDB commands executed upon debugger startup.
|**targetCreateCommands**|[string]| LLDB commands executed to create debug target.
|**preRunCommands** |[string]| LLDB commands executed just before launching/attaching the debuggee.
-|**processCreateCommands**|[string]| LLDB commands executed to created/attach the debuggee process.
+|**processCreateCommands**|[string]| LLDB commands executed to create/attach the debuggee process.
|**postRunCommands** |[string]| LLDB commands executed just after launching/attaching the debuggee.
|**exitCommands** |[string]| LLDB commands executed at the end of the debugging session.
|**expressions** |string| The default expression evaluator type: `simple`, `python` or `native`. See [Expressions](#expressions).
@@ -85,7 +85,7 @@ These attributes are applicable when the "launch" initiation method is selected:
|**env** |dictionary| Environment variables to set in addition to the ones inherited from the parent process environment (unless LLDB's `target.inherit-env` setting has been set to `false`, in which case the initial process environment is empty). You may refer to existing environment variables using `${env:NAME}` syntax. For example, in order to alter the inherited `PATH` variable, you can do this: `"PATH":"${env:HOME}/bin:${env:PATH}"`.
|**envFile** |string| Path of the file to read the environment variables from. Note that `env` entries will override `envPath` entries.
|**stdio** |string ❘ [string] ❘ dictionary| See [Stdio Redirection](#stdio-redirection).
-|**terminal** |string| Destination for debuggee stdio streams:
- `console` for DEBUG CONSOLE
- `integrated` (default) for VSCode integrated terminal
- `external` for a new terminal window
+|**terminal** |string| Destination for debuggee's stdio streams: - `console` for DEBUG CONSOLE
- `integrated` (default) for VSCode integrated terminal
- `external` for a new terminal window
|**stopOnEntry** |boolean| Whether to stop debuggee immediately after launching.
Operations performed for launch:
@@ -96,7 +96,7 @@ Operations performed for launch:
- Otherwise, target is created from the binary pointed to by the `program` attribute.
- Target properties are configured using `args`, `env`, `cwd`, `stdio`, etc, configuration attributes.
- Breakpoints are created.
-- The `preRunCommands` sequence is executed. These commands may alter debug target configuration (e.g. alter args or env).
+- The `preRunCommands` sequence is executed. These commands may alter debug target configuration (e.g. args or env).
- The debuggee process is created:
- If `processCreateCommands` attribute is present, this command sequence is executed. These are expected to have created
a process corresponding to the debug target.
@@ -127,7 +127,7 @@ These attributes are applicable when the "attach" initiation method is selected:
|attribute |type | |
|-------------------|--------|---------|
|**program** |string |Path of the executable file.
-|**pid** |number |Process id to attach to. **pid** may be omitted, in which case debugger will attempt to locate an already running instance of the program. You may also put `${command:pickProcess}` or `${command:pickMyProcess}` here to choose a process interactively.
+|**pid** |number |Process id to attach to. **pid** may be omitted, in which case debugger will attempt to locate an already running instance of the program. You may also use [`${command:pickProcess}` or `${command:pickMyProcess}`](#pick-process-command) here to choose process interactively.
|**stopOnEntry** |boolean |Whether to stop the debuggee immediately after attaching.
|**waitFor** |boolean |Wait for the process to launch.
@@ -365,7 +365,7 @@ target modules load --file ${workspaceFolder}/build/debuggee -s ` command:
```
## Source Path Remapping
-Source path remapping is helpful in cases when program's source code is located in a different
-directory then it was in at build time (for example, if a build server was used).
+Source path remapping is helpful when the program's source code is located in a different directory than it was at build time (for example, if a build server was used).
A source map consists of pairs of "from" and "to" path prefixes. When the debugger encounters a source
file path beginning with one of the "from" prefixes, it will substitute the corresponding "to" prefix
@@ -585,7 +584,7 @@ views](https://lldb.llvm.org/use/varformats.html) of the debuggee variables. Fo
`std::vector` or comparing `std::string` to a string literal should "just work".
The followng features are supported:
-- References to variables: all identifiers are assumed to refer to variables in the debuggee's current stack frame.
+- References to variables: all identifiers are assumed to refer to variables in the debuggee current stack frame.
The identifiers may be qualified with namespaces and template parameters (e.g. `std::numeric_limits::digits`).
- Embedded [native expressions](#native-expressions): these must be delimited with `${` and `}`.
- Literals: integers, floats and strings, `True`, `False`.
@@ -627,42 +626,70 @@ thus they are often not as convenient as "simple" or "python" expressions.
## Debugger API
-CodeLLDB provides extended Python API via the `debugger` module (which is auto-imported into debugger's main script context).
-This module exports the following functions:
-
-def **evaluate(expression: `str`, unwrap=False) -> `Value` | `lldb.SBValue`** : Performs dynamic evaluation of [native expressions](#native-expressions) returning instances of [`Value`](#value).
-- **expression**: The expression to evaluate.
-- **unwrap**: Whether to unwrap the result and return it as `lldb.SBValue`.
-
-**unwrap(obj: `Value`) -> `lldb.SBValue`** : Extracts an [`lldb.SBValue`](https://lldb.llvm.org/python_api/lldb.SBValue.html) from [`Value`](#value).
-
-**wrap(obj: `lldb.SBValue`) -> `Value`** : Wraps [`lldb.SBValue`](https://lldb.llvm.org/python_api/lldb.SBValue.html) in a [`Value`](#value) object.
-
-**create_webview(html: `str`=None, title: `str`=None, view_column: `int`=None, preserve_focus: `bool`=False, enable_find_widget: `bool`=False, retain_context_when_hidden: `bool`=False, enable_scripts: `bool`=False) -> Webview** :
-Create a [Webview](#webview), which can be used to display HTML content in VSCode UI.
-
-**display_html(html: `str`, title: `str` = None, position: `int` = None, reveal: `bool` = False)** : (deprecated - use webviews instead) Displays content in a VSCode Webview panel:
-- **html**: HTML markup to display.
-- **title**: Title of the panel. Defaults to the name of the current launch configuration.
-- **position**: Position (column) of the panel. The allowed range is 1 through 3.
-- **reveal**: Whether to reveal the panel if one already exists.
+CodeLLDB provides extended Python API via the `codelldb` module (also aliased as `debugger`),
+which is auto-imported into debugger's main script context:
+
+```python
+# codelldb
+
+def get_config(name: str, default: Any = None) -> Any:
+ '''Retrieve a configuration value from the adapter settings.
+ name: Dot-separated path of the setting to retrieve. For example, 'foo.bar', will retrieve the value of `lldb.script.foo.bar`.
+ default: The default value to return if the configuration value is not found.
+ '''
+def evaluate(expr: str, unwrap: bool = False) -> Value | lldb.SBValue:
+ '''Performs dynamic evaluation of native expressions returning instances of Value or SBValue.
+ expression: The expression to evaluate.
+ unwrap: Whether to unwrap the result and return it as lldb.SBValue
+ '''
+def wrap(obj: lldb.SBValue) -> Value:
+ '''Extracts an lldb.SBValue from Value'''
+def unwrap(obj: Value) -> lldb.SBValue:
+ '''Wraps lldb.SBValue in a Value object'''
+def create_webview(html: Optional[str] = None, title: Optional[str] = None, view_column: Optional[int] = None,
+ preserve_focus: bool = False, enable_find_widget: bool = False,
+ retain_context_when_hidden: bool = False, enable_scripts: bool = False):
+ '''Create a webview panel.
+ html: HTML content to display in the webview. May be later replaced via Webview.set_html().
+ title: Panel title.
+ view_column: Column in which to show the webview.
+ preserve_focus: Whether to preserve focus in the current editor when revealing the webview.
+ enable_find_widget: Controls if the find widget is enabled in the panel.
+ retain_context_when_hidden: Controls if the webview panel retains its context when it is hidden.
+ enable_scripts: Controls if scripts are enabled in the webview.
+ '''
+```
## Webview
-The Webview class provides a simplified interface to VSCode [Webview](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel).
-
-class **Webview:**
- - **set_html(html: `str`)**: Set HTML contents of the webview.
- - **reveal(view_column: `int`=None, preserve_focus: `bool`=False)**: Show the webview panel in a given column.
- - **post_message(message: `object`)**: Post a message to the webview content.
- - **dispose()**: Destroy the webview panel
- - **on_did_receive_message: `Event[object]`**: Fired when the webview content posts a message.
- - **on_did_dispose: `Event`**: Fired when the webview panel is disposed (either by the user or by calling dispose()).
+A simplified interface for [webview panels](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel).
+
+```python
+class Webview:
+ def dispose(self):
+ '''Destroy webview panel.'''
+ def set_html(self, html: str):
+ '''Set HTML contents of the webview.'''
+ def reveal(self, view_column: Optional[int] = None, preserve_focus: bool = False):
+ '''Show the webview panel in a given column.'''
+ def post_message(self, message: Any):
+ '''Post a message to the webview content.'''
+ interface.send_message(dict(message='webviewPostMessage', id=self.id, inner=message))
+ @property
+ def on_did_receive_message(self) -> Event:
+ '''Fired when webview content posts a new message.'''
+ @property
+ def on_did_dispose(self) -> Event:
+ '''Fired when the webview panel is disposed (either by the user or by calling dispose())'''
+```
## Event
-class **Event[T]:**
- - **add(handler: `Callable[T]`)**: Add event listener.
- - **remove(handler: `Callable[T]`)**: Remove event listener.
-
+```python
+class Event:
+ def add(self, listener: Callable[[Any]]):
+ '''Add an event listener.'''
+ def remove(self, listener: Callable[[Any]]):
+ '''Remove an event listener.'''
+```
## Value
`Value` objects ([source](adapter/scripts/codelldb/value.py)) are proxy wrappers around [`lldb.SBValue`](https://lldb.llvm.org/python_api/lldb.SBValue.html),
@@ -700,19 +727,18 @@ this configuration entry: `"lldb.adapterEnv": {"LLDB_DEBUGSERVER_PATH": "`commands` - treat debug console input as debugger commands. In order to evaluate an expression, prefix it with '?' (question mark).",`evaluate` - treat DEBUG CONSOLE input as expressions. In order to execute a debugger command, prefix it with '/cmd ' or '\`' (backtick), `split` - (experimental) use the DEBUG CONSOLE for evaluation of expressions, open a separate terminal for LLDB console.
+|**lldb.script** |Configuration settings provided to Python scripts running in the context of CodeLLDB. These may be read via [`get_config()`](#debugger-api).
+
## Advanced
| | |
diff --git a/adapter/scripts/codelldb/api.py b/adapter/scripts/codelldb/api.py
index f7e7f2b3..68938dbb 100644
--- a/adapter/scripts/codelldb/api.py
+++ b/adapter/scripts/codelldb/api.py
@@ -1,38 +1,58 @@
import lldb
import warnings
import __main__
+from typing import Any, Optional, Union
from . import interface
from .value import Value
from .webview import Webview
-def evaluate(expr, unwrap=False):
+def get_config(name: str, default: Any = None) -> Any:
+ '''Retrieve a configuration value from the adapter settings.
+ name: Dot-separated path of the setting to retrieve. For example, 'foo.bar', will retrieve the value of `lldb.script.foo.bar`.
+ default: The default value to return if the configuration value is not found.
+ '''
+ internal_dict = interface.get_instance_dict(lldb.debugger)
+ settings = internal_dict['adapter_settings'].get('scriptConfig')
+ for segment in name.split('.'):
+ if settings is None:
+ return default
+ settings = settings.get(segment)
+ return settings
+
+
+def evaluate(expr: str, unwrap: bool = False) -> Union[Value, lldb.SBValue]:
+ '''Performs dynamic evaluation of native expressions returning instances of Value or SBValue.
+ expression: The expression to evaluate.
+ unwrap: Whether to unwrap the result and return it as lldb.SBValue
+ '''
value = interface.nat_eval(lldb.frame, expr)
return Value.unwrap(value) if unwrap else value
-def wrap(obj):
+def wrap(obj: lldb.SBValue) -> Value:
+ '''Extracts an lldb.SBValue from Value'''
return obj if type(obj) is Value else Value(obj)
-def unwrap(obj):
+def unwrap(obj: Value) -> lldb.SBValue:
+ '''Wraps lldb.SBValue in a Value object'''
return Value.unwrap(obj)
-def get_config(name, default=None):
- internal_dict = interface.get_instance_dict(lldb.debugger)
- settings = internal_dict['adapter_settings'].get('scriptConfig')
- for segment in name.split('.'):
- if settings is None:
- return default
- settings = settings.get(segment)
- return settings
-
-
-def create_webview(html=None, title=None, view_column=None, preserve_focus=False,
- enable_find_widget=False, retain_context_when_hidden=False,
- enable_scripts=False):
+def create_webview(html: Optional[str] = None, title: Optional[str] = None, view_column: Optional[int] = None,
+ preserve_focus: bool = False, enable_find_widget: bool = False,
+ retain_context_when_hidden: bool = False, enable_scripts: bool = False):
+ '''Create a [webview panel](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel).
+ html: HTML content to display in the webview. May be later replaced via Webview.set_html().
+ title: Panel title.
+ view_column: Column in which to show the webview.
+ preserve_focus: Whether to preserve focus in the current editor when revealing the webview.
+ enable_find_widget: Controls if the find widget is enabled in the panel.
+ retain_context_when_hidden: Controls if the webview panel retains its context when it is hidden.
+ enable_scripts: Controls if scripts are enabled in the webview.
+ '''
webview = Webview()
interface.send_message(dict(message='webviewCreate',
id=webview.id,
@@ -47,7 +67,10 @@ def create_webview(html=None, title=None, view_column=None, preserve_focus=False
return webview
-def display_html(html, title=None, position=None, reveal=False):
+def display_html(html: str, title: Optional[str] = None, position: Optional[int] = None, reveal: bool = False):
+ '''Display HTML content in a webview panel.
+ display_html is **deprecated**, use create_webview instead.
+ '''
global html_webview
if html_webview is None:
warnings.warn("display_html is deprecated, use create_webview instead", DeprecationWarning)
diff --git a/adapter/scripts/codelldb/event.py b/adapter/scripts/codelldb/event.py
index 1598f611..a3006cfd 100644
--- a/adapter/scripts/codelldb/event.py
+++ b/adapter/scripts/codelldb/event.py
@@ -1,13 +1,19 @@
+from typing import Callable, Any
+
+
class Event:
def __init__(self):
self._listeners = []
- def add(self, listener):
+ def add(self, listener: Callable[[Any], None]):
+ '''Add an event listener.'''
self._listeners.append(listener)
- def remove(self, listener):
+ def remove(self, listener: Callable[[Any], None]):
+ '''Remove an event listener.'''
self._listeners.remove(listener)
- def emit(self, message):
+ def emit(self, message: Any):
+ '''Notify all listeners.'''
for listener in self._listeners:
listener(message)
diff --git a/adapter/scripts/codelldb/webview.py b/adapter/scripts/codelldb/webview.py
index 7d472471..c9dc6e91 100644
--- a/adapter/scripts/codelldb/webview.py
+++ b/adapter/scripts/codelldb/webview.py
@@ -1,3 +1,4 @@
+from typing import Any, Optional
from . import interface
from .event import Event
@@ -5,34 +6,50 @@
class Webview:
+ '''A simplified interface for [webview panels](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel).'''
+
def __init__(self):
global view_id
view_id += 1
self.id = view_id
- self.on_did_receive_message = Event()
- self.on_did_dispose = Event()
+ self._on_did_receive_message = Event()
+ self._on_did_dispose = Event()
interface.on_did_receive_message.add(self._message_handler)
def _message_handler(self, message):
if message.get('id', None) == self.id:
message_type = message.get('message', None)
if message_type == 'webviewDidReceiveMessage':
- self.on_did_receive_message.emit(message.get('inner', None))
+ self._on_did_receive_message.emit(message.get('inner', None))
elif message_type == 'webviewDidDispose':
- self.on_did_dispose.emit(message.get('inner', None))
+ self._on_did_dispose.emit(message.get('inner', None))
def __del__(self):
interface.on_did_receive_message.remove(self._message_handler)
def dispose(self):
+ '''Destroy webview panel.'''
interface.send_message(dict(message='webviewDispose', id=self.id))
- def set_html(self, html):
+ def set_html(self, html: str):
+ '''Set HTML contents of the webview.'''
interface.send_message(dict(message='webviewSetHtml', id=self.id, html=html))
- def reveal(self, view_column=None, preserve_focus=False):
+ def reveal(self, view_column: Optional[int] = None, preserve_focus: bool = False):
+ '''Show the webview panel in a given column.'''
interface.send_message(dict(message='webviewReveal', id=self.id,
- viewColumn=view_column, preserveFocus=preserve_focus))
+ viewColumn=view_column, preserveFocus=preserve_focus))
- def post_message(self, message):
+ def post_message(self, message: Any):
+ '''Post a message to the webview content.'''
interface.send_message(dict(message='webviewPostMessage', id=self.id, inner=message))
+
+ @property
+ def on_did_receive_message(self) -> Event:
+ '''Fired when webview content posts a new message.'''
+ return self._on_did_receive_message
+
+ @property
+ def on_did_dispose(self) -> Event:
+ '''Fired when the webview panel is disposed (either by the user or by calling dispose())'''
+ return self._on_did_dispose