[Lldb-commits] [lldb] [llvm] [LLDB] Include components of settings paths in apropos search (PR #194873)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Tue May 5 05:53:13 PDT 2026
https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/194873
>From 4c41d422b4545a48c621a481e182babcee683e85 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 29 Apr 2026 13:11:32 +0000
Subject: [PATCH 01/11] refactor
---
.../Interpreter/OptionValueProperties.cpp | 39 +++++++++----------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index def6cc462f76a..1908aed85fd3d 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -466,28 +466,27 @@ void OptionValueProperties::Apropos(
llvm::StringRef keyword,
std::vector<const Property *> &matching_properties) const {
const size_t num_properties = m_properties.size();
- StreamString strm;
for (size_t i = 0; i < num_properties; ++i) {
const Property *property = ProtectedGetPropertyAtIndex(i);
- if (property) {
- const OptionValueProperties *properties =
- property->GetValue()->GetAsProperties();
- if (properties) {
- properties->Apropos(keyword, matching_properties);
- } else {
- bool match = false;
- llvm::StringRef name = property->GetName();
- if (name.contains_insensitive(keyword))
- match = true;
- else {
- llvm::StringRef desc = property->GetDescription();
- if (desc.contains_insensitive(keyword))
- match = true;
- }
- if (match) {
- matching_properties.push_back(property);
- }
- }
+ if (!property)
+ continue;
+
+ if (const OptionValueProperties *properties =
+ property->GetValue()->GetAsProperties()) {
+ properties->Apropos(keyword, matching_properties);
+ continue;
+ }
+
+ if (llvm::StringRef name = property->GetName();
+ name.contains_insensitive(keyword)) {
+ matching_properties.push_back(property);
+ continue;
+ }
+
+ if (llvm::StringRef desc = property->GetDescription();
+ desc.contains_insensitive(keyword)) {
+ matching_properties.push_back(property);
+ continue;
}
}
}
>From f3cc98341ccb4aab5ed262a02fbd4c4b07ebdbbc Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 29 Apr 2026 12:58:14 +0000
Subject: [PATCH 02/11] wip
---
.../Interpreter/OptionValueProperties.cpp | 7 ++++++
.../API/commands/settings/TestSettings.py | 24 +++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index 1908aed85fd3d..65d913137930f 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -483,6 +483,13 @@ void OptionValueProperties::Apropos(
continue;
}
+ if (StreamString qualified_name;
+ property->DumpQualifiedName(qualified_name) &&
+ qualified_name.GetString().contains_insensitive(keyword)) {
+ matching_properties.push_back(property);
+ continue;
+ }
+
if (llvm::StringRef desc = property->GetDescription();
desc.contains_insensitive(keyword)) {
matching_properties.push_back(property);
diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py
index 8410befe399a3..e3302cb9b9aa5 100644
--- a/lldb/test/API/commands/settings/TestSettings.py
+++ b/lldb/test/API/commands/settings/TestSettings.py
@@ -26,6 +26,30 @@ def test_apropos_should_also_search_settings_description(self):
],
)
+ def test_apropos_should_also_search_settings_qualified_name(self):
+ """Test that 'apropos' command searches the qualified name ("a.b.c.d") of settings not just
+ the name ("d")."""
+
+ # 'qemu-user' is one component of the qualified name.
+ self.expect(
+ "apropos 'qemu-user'",
+ substrs=[
+ "platform.plugin.qemu-user.architecture",
+ "platform.plugin.qemu-user.emulator-args",
+ ],
+ )
+
+ # Should be able to search for strings that overlap > 1 component of the
+ # qualified name.
+ self.expect(
+ "apropos 'qemu-user.emulator-'",
+ substrs=[
+ "platform.plugin.qemu-user.emulator-args",
+ "platform.plugin.qemu-user.emulator-env-vars",
+ "platform.plugin.qemu-user.emulator-path",
+ ],
+ )
+
def test_set_interpreter_repeat_prev_command(self):
"""Test the `interpreter.repeat-previous-command` setting."""
self.build()
>From 4b8ba32c41955d84ea8aecba3b6e08305fcb9bc3 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 29 Apr 2026 14:09:50 +0000
Subject: [PATCH 03/11] the faster way
---
.../lldb/Interpreter/OptionValueProperties.h | 2 +
.../Interpreter/OptionValueProperties.cpp | 51 +++++++++++++++----
2 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h
index 21da8e584a7b4..84118a06a61ff 100644
--- a/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -84,6 +84,8 @@ class OptionValueProperties
return ProtectedGetPropertyAtIndex(idx);
}
+ size_t GetNumProperties() const { return m_properties.size(); }
+
// Property can be a property path like
// "target.process.extra-startup-command"
virtual const Property *
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index 65d913137930f..2248c7984ee55 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -462,6 +462,23 @@ void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
}
}
+// This function flattens a nested set of properties. This is what we want for
+// search results. If we didn't do this, search results would be presented
+// split up by type of setting.
+static void
+FlattenProperties(const OptionValueProperties *properties,
+ std::vector<const Property *> &matching_properties) {
+ size_t num_child_properties = properties->GetNumProperties();
+ for (size_t i = 0; i < num_child_properties; ++i)
+ if (auto property = properties->GetPropertyAtIndex(i)) {
+ if (auto children = property->GetValue()->GetAsProperties()) {
+ FlattenProperties(children, matching_properties);
+ } else {
+ matching_properties.push_back(property);
+ }
+ }
+}
+
void OptionValueProperties::Apropos(
llvm::StringRef keyword,
std::vector<const Property *> &matching_properties) const {
@@ -471,21 +488,37 @@ void OptionValueProperties::Apropos(
if (!property)
continue;
+ // The qualified name includes the category parts. For example
+ // "platform.plugin.qemu-user.qemu-user".
+ StreamString qualified_name_strm;
+ std::optional<llvm::StringRef> qualified_name_str;
+ if (property->DumpQualifiedName(qualified_name_strm))
+ qualified_name_str = qualified_name_strm.GetString();
+
+ // Some properties are a group of other priorities.
if (const OptionValueProperties *properties =
property->GetValue()->GetAsProperties()) {
- properties->Apropos(keyword, matching_properties);
- continue;
- }
+ // If the keyword is already in the qualified name, any nested
+ // settings would match too and we can just add them, skipping
+ // getting their qualified names too.
+ if (qualified_name_str &&
+ qualified_name_str->contains_insensitive(keyword)) {
+ FlattenProperties(properties, matching_properties);
+ } else {
+ // Search in all the nested settings.
+ properties->Apropos(keyword, matching_properties);
+ }
- if (llvm::StringRef name = property->GetName();
- name.contains_insensitive(keyword)) {
- matching_properties.push_back(property);
continue;
}
- if (StreamString qualified_name;
- property->DumpQualifiedName(qualified_name) &&
- qualified_name.GetString().contains_insensitive(keyword)) {
+ if (qualified_name_str) {
+ if (qualified_name_str->contains_insensitive(keyword)) {
+ matching_properties.push_back(property);
+ continue;
+ }
+ } else if (llvm::StringRef name = property->GetName();
+ name.contains_insensitive(keyword)) {
matching_properties.push_back(property);
continue;
}
>From f9f8e8ab5c2cb960465d8d5b91fa588d7362a6a4 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 30 Apr 2026 12:06:35 +0000
Subject: [PATCH 04/11] Revert " the faster way"
This reverts commit 81a21838ec9d4512e4a3518919414df62fba080b.
---
.../lldb/Interpreter/OptionValueProperties.h | 2 -
.../Interpreter/OptionValueProperties.cpp | 51 ++++---------------
2 files changed, 9 insertions(+), 44 deletions(-)
diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h
index 84118a06a61ff..21da8e584a7b4 100644
--- a/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -84,8 +84,6 @@ class OptionValueProperties
return ProtectedGetPropertyAtIndex(idx);
}
- size_t GetNumProperties() const { return m_properties.size(); }
-
// Property can be a property path like
// "target.process.extra-startup-command"
virtual const Property *
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index 2248c7984ee55..65d913137930f 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -462,23 +462,6 @@ void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
}
}
-// This function flattens a nested set of properties. This is what we want for
-// search results. If we didn't do this, search results would be presented
-// split up by type of setting.
-static void
-FlattenProperties(const OptionValueProperties *properties,
- std::vector<const Property *> &matching_properties) {
- size_t num_child_properties = properties->GetNumProperties();
- for (size_t i = 0; i < num_child_properties; ++i)
- if (auto property = properties->GetPropertyAtIndex(i)) {
- if (auto children = property->GetValue()->GetAsProperties()) {
- FlattenProperties(children, matching_properties);
- } else {
- matching_properties.push_back(property);
- }
- }
-}
-
void OptionValueProperties::Apropos(
llvm::StringRef keyword,
std::vector<const Property *> &matching_properties) const {
@@ -488,37 +471,21 @@ void OptionValueProperties::Apropos(
if (!property)
continue;
- // The qualified name includes the category parts. For example
- // "platform.plugin.qemu-user.qemu-user".
- StreamString qualified_name_strm;
- std::optional<llvm::StringRef> qualified_name_str;
- if (property->DumpQualifiedName(qualified_name_strm))
- qualified_name_str = qualified_name_strm.GetString();
-
- // Some properties are a group of other priorities.
if (const OptionValueProperties *properties =
property->GetValue()->GetAsProperties()) {
- // If the keyword is already in the qualified name, any nested
- // settings would match too and we can just add them, skipping
- // getting their qualified names too.
- if (qualified_name_str &&
- qualified_name_str->contains_insensitive(keyword)) {
- FlattenProperties(properties, matching_properties);
- } else {
- // Search in all the nested settings.
- properties->Apropos(keyword, matching_properties);
- }
+ properties->Apropos(keyword, matching_properties);
+ continue;
+ }
+ if (llvm::StringRef name = property->GetName();
+ name.contains_insensitive(keyword)) {
+ matching_properties.push_back(property);
continue;
}
- if (qualified_name_str) {
- if (qualified_name_str->contains_insensitive(keyword)) {
- matching_properties.push_back(property);
- continue;
- }
- } else if (llvm::StringRef name = property->GetName();
- name.contains_insensitive(keyword)) {
+ if (StreamString qualified_name;
+ property->DumpQualifiedName(qualified_name) &&
+ qualified_name.GetString().contains_insensitive(keyword)) {
matching_properties.push_back(property);
continue;
}
>From 65118916073ae9a431e87702545b636fa31315ea Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 30 Apr 2026 12:06:44 +0000
Subject: [PATCH 05/11] get property and property nodes into 2 lists
---
.../lldb/Core/UserSettingsController.h | 5 ++-
.../lldb/Interpreter/OptionValueProperties.h | 3 +-
lldb/source/Commands/CommandObjectApropos.cpp | 8 ++--
lldb/source/Core/UserSettingsController.cpp | 10 ++---
.../Interpreter/OptionValueProperties.cpp | 42 +++++++++++--------
5 files changed, 38 insertions(+), 30 deletions(-)
diff --git a/lldb/include/lldb/Core/UserSettingsController.h b/lldb/include/lldb/Core/UserSettingsController.h
index 29e892fdba45b..a1ba2d32915c8 100644
--- a/lldb/include/lldb/Core/UserSettingsController.h
+++ b/lldb/include/lldb/Core/UserSettingsController.h
@@ -62,8 +62,9 @@ class Properties {
virtual void DumpAllDescriptions(CommandInterpreter &interpreter,
Stream &strm) const;
- size_t Apropos(llvm::StringRef keyword,
- std::vector<const Property *> &matching_properties) const;
+ void Apropos(llvm::StringRef keyword,
+ std::vector<const Property *> &matching_properties,
+ std::vector<const Property *> &matching_property_prefixes) const;
// We sometimes need to introduce a setting to enable experimental features,
// but then we don't want the setting for these to cause errors when the
diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h
index 21da8e584a7b4..d9f74c802c433 100644
--- a/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -58,7 +58,8 @@ class OptionValueProperties
Stream &strm) const;
void Apropos(llvm::StringRef keyword,
- std::vector<const Property *> &matching_properties) const;
+ std::vector<const Property *> &matching_properties,
+ std::vector<const Property *> &matching_property_prefixes) const;
void Initialize(const PropertyCollectionDefinition &setting_definitions);
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
index dc31e60f7fc2a..0159c502b2c14 100644
--- a/lldb/source/Commands/CommandObjectApropos.cpp
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -73,8 +73,8 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
// Find all the properties matching the search word.
size_t properties_max_len = 0;
std::vector<const Property *> properties;
- const size_t num_properties =
- GetDebugger().Apropos(search_word, properties);
+ std::vector<const Property *> property_prefixes;
+ GetDebugger().Apropos(search_word, properties, property_prefixes);
for (const Property *prop : properties) {
StreamString qualified_name;
prop->DumpQualifiedName(qualified_name);
@@ -82,7 +82,7 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
std::max(properties_max_len, qualified_name.GetString().size());
}
- if (num_properties == 0) {
+ if (properties.size() == 0) {
result.AppendMessageWithFormatv(
"No settings found pertaining to '{0}'. "
"Try 'settings show' to see a complete list of "
@@ -95,7 +95,7 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
search_word);
const bool dump_qualified_name = true;
- for (size_t i = 0; i < num_properties; ++i)
+ for (size_t i = 0; i < properties.size(); ++i)
properties[i]->DumpDescription(
m_interpreter, result.GetOutputStream(), properties_max_len,
dump_qualified_name, highlight);
diff --git a/lldb/source/Core/UserSettingsController.cpp b/lldb/source/Core/UserSettingsController.cpp
index 206b2072ddaf2..c7c33b947d1ab 100644
--- a/lldb/source/Core/UserSettingsController.cpp
+++ b/lldb/source/Core/UserSettingsController.cpp
@@ -75,11 +75,11 @@ Status Properties::DumpPropertyValue(const ExecutionContext *exe_ctx,
dump_mask, is_json);
}
-size_t
-Properties::Apropos(llvm::StringRef keyword,
- std::vector<const Property *> &matching_properties) const {
- m_collection_sp->Apropos(keyword, matching_properties);
- return matching_properties.size();
+void Properties::Apropos(
+ llvm::StringRef keyword, std::vector<const Property *> &matching_properties,
+ std::vector<const Property *> &matching_property_prefixes) const {
+ m_collection_sp->Apropos(keyword, matching_properties,
+ matching_property_prefixes);
}
llvm::StringRef Properties::GetExperimentalSettingsName() {
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index 65d913137930f..df3f2218284f2 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -463,37 +463,43 @@ void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
}
void OptionValueProperties::Apropos(
- llvm::StringRef keyword,
- std::vector<const Property *> &matching_properties) const {
+ llvm::StringRef keyword, std::vector<const Property *> &matching_properties,
+ std::vector<const Property *> &matching_property_prefixes) const {
const size_t num_properties = m_properties.size();
for (size_t i = 0; i < num_properties; ++i) {
const Property *property = ProtectedGetPropertyAtIndex(i);
if (!property)
continue;
- if (const OptionValueProperties *properties =
- property->GetValue()->GetAsProperties()) {
- properties->Apropos(keyword, matching_properties);
- continue;
- }
+ const OptionValueProperties *properties =
+ property->GetValue()->GetAsProperties();
+ if (properties)
+ properties->Apropos(keyword, matching_properties,
+ matching_property_prefixes);
- if (llvm::StringRef name = property->GetName();
- name.contains_insensitive(keyword)) {
- matching_properties.push_back(property);
- continue;
- }
+ bool matched = false;
+ // TODO: do we need this at all? It allows you to look for a.b?
if (StreamString qualified_name;
property->DumpQualifiedName(qualified_name) &&
- qualified_name.GetString().contains_insensitive(keyword)) {
- matching_properties.push_back(property);
- continue;
- }
+ qualified_name.GetString().contains_insensitive(keyword))
+ matched = true;
+
+ if (llvm::StringRef name = property->GetName();
+ !matched && name.contains_insensitive(keyword))
+ matched = true;
if (llvm::StringRef desc = property->GetDescription();
- desc.contains_insensitive(keyword)) {
- matching_properties.push_back(property);
+ !matched && desc.contains_insensitive(keyword))
+ matched = true;
+
+ if (!matched)
continue;
+
+ if (properties) {
+ matching_property_prefixes.push_back(property);
+ } else {
+ matching_properties.push_back(property);
}
}
}
>From 7bf846b8cfdcb345f3b9ff2f03dd8f45583f77cb Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 30 Apr 2026 13:09:32 +0000
Subject: [PATCH 06/11] print property prefixes
---
lldb/source/Commands/CommandObjectApropos.cpp | 44 ++++++++++++++-----
.../Interpreter/OptionValueProperties.cpp | 6 ---
lldb/source/Interpreter/Property.cpp | 10 +++--
.../API/commands/settings/TestSettings.py | 22 +++-------
4 files changed, 45 insertions(+), 37 deletions(-)
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
index 0159c502b2c14..8c594893c06e7 100644
--- a/lldb/source/Commands/CommandObjectApropos.cpp
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -82,7 +82,7 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
std::max(properties_max_len, qualified_name.GetString().size());
}
- if (properties.size() == 0) {
+ if (properties.empty() && property_prefixes.empty()) {
result.AppendMessageWithFormatv(
"No settings found pertaining to '{0}'. "
"Try 'settings show' to see a complete list of "
@@ -90,18 +90,40 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
args[0].c_str());
} else {
- result.AppendMessageWithFormatv(
- "\nThe following settings variables may relate to '{0}': \n\n",
- search_word);
-
- const bool dump_qualified_name = true;
- for (size_t i = 0; i < properties.size(); ++i)
- properties[i]->DumpDescription(
- m_interpreter, result.GetOutputStream(), properties_max_len,
- dump_qualified_name, highlight);
return_status = eReturnStatusSuccessFinishResult;
- }
+ if (!property_prefixes.empty()) {
+ result.AppendMessageWithFormatv(
+ "\nThe following settings prefixes may relate to '{0}': \n\n",
+ search_word);
+
+ auto &out_strm = result.GetOutputStream();
+ out_strm.IndentMore();
+ for (auto prefix : property_prefixes) {
+ StreamString qual_name_strm;
+ // TODO: highlight!!!!
+ if (prefix->DumpQualifiedName(qual_name_strm)) {
+ result.GetOutputStream().Indent();
+ result.GetOutputStream() << qual_name_strm.GetString() << '\n';
+ }
+ }
+ out_strm.IndentLess();
+
+ result.AppendMessageWithFormatv(
+ "\n(use 'settings list' to show settings with a given prefix)");
+ }
+
+ if (!properties.empty()) {
+ result.AppendMessageWithFormatv(
+ "\nThe following settings variables may relate to '{0}': \n\n",
+ search_word);
+
+ const bool dump_qualified_name = true;
+ for (auto property : properties)
+ property->DumpDescription(m_interpreter, result.GetOutputStream(),
+ properties_max_len, dump_qualified_name, highlight);
+ }
+ }
result.SetStatus(return_status);
} else {
result.AppendError("'' is not a valid search word.\n");
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index df3f2218284f2..3b0cdd453b0bc 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -479,12 +479,6 @@ void OptionValueProperties::Apropos(
bool matched = false;
- // TODO: do we need this at all? It allows you to look for a.b?
- if (StreamString qualified_name;
- property->DumpQualifiedName(qualified_name) &&
- qualified_name.GetString().contains_insensitive(keyword))
- matched = true;
-
if (llvm::StringRef name = property->GetName();
!matched && name.contains_insensitive(keyword))
matched = true;
diff --git a/lldb/source/Interpreter/Property.cpp b/lldb/source/Interpreter/Property.cpp
index b049b765e520e..7684e193106da 100644
--- a/lldb/source/Interpreter/Property.cpp
+++ b/lldb/source/Interpreter/Property.cpp
@@ -236,9 +236,13 @@ Property::Property(llvm::StringRef name, llvm::StringRef desc, bool is_global,
bool Property::DumpQualifiedName(Stream &strm) const {
if (!m_name.empty()) {
- if (m_value_sp->DumpQualifiedName(strm))
- strm.PutChar('.');
- strm << m_name;
+ bool has_sub_properties = static_cast<bool>(m_value_sp->GetAsProperties());
+ bool dumped_something = m_value_sp->DumpQualifiedName(strm);
+ if (!has_sub_properties) {
+ if (dumped_something)
+ strm.PutChar('.');
+ strm << m_name;
+ }
return true;
}
return false;
diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py
index e3302cb9b9aa5..5035a3f23632d 100644
--- a/lldb/test/API/commands/settings/TestSettings.py
+++ b/lldb/test/API/commands/settings/TestSettings.py
@@ -26,27 +26,15 @@ def test_apropos_should_also_search_settings_description(self):
],
)
- def test_apropos_should_also_search_settings_qualified_name(self):
- """Test that 'apropos' command searches the qualified name ("a.b.c.d") of settings not just
- the name ("d")."""
+ def test_apropos_searches_settings_prefixes(self):
+ """Test that 'apropos' command searches the prefixes of the qualified names."""
- # 'qemu-user' is one component of the qualified name.
self.expect(
"apropos 'qemu-user'",
substrs=[
- "platform.plugin.qemu-user.architecture",
- "platform.plugin.qemu-user.emulator-args",
- ],
- )
-
- # Should be able to search for strings that overlap > 1 component of the
- # qualified name.
- self.expect(
- "apropos 'qemu-user.emulator-'",
- substrs=[
- "platform.plugin.qemu-user.emulator-args",
- "platform.plugin.qemu-user.emulator-env-vars",
- "platform.plugin.qemu-user.emulator-path",
+ "The following settings prefixes may relate to 'qemu-user':\n"
+ " platform.plugin.qemu-user\n"
+ "\n"
],
)
>From ca730e299c1904dc323c5392d5d39e76aba9f284 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 5 May 2026 10:04:27 +0000
Subject: [PATCH 07/11] updates
---
.../lldb/Core/UserSettingsController.h | 2 +-
lldb/include/lldb/Interpreter/OptionValue.h | 4 ++-
.../lldb/Interpreter/OptionValueProperties.h | 2 +-
lldb/include/lldb/Interpreter/Property.h | 4 ++-
lldb/source/Commands/CommandObjectApropos.cpp | 22 ++++++-------
lldb/source/Core/UserSettingsController.cpp | 4 +--
lldb/source/Interpreter/OptionValue.cpp | 7 +++--
.../Interpreter/OptionValueProperties.cpp | 6 ++--
lldb/source/Interpreter/Property.cpp | 7 +++--
.../formatting/TestAproposFormatting.py | 31 ++++++++++++++++---
.../API/commands/settings/TestSettings.py | 7 +++--
11 files changed, 62 insertions(+), 34 deletions(-)
diff --git a/lldb/include/lldb/Core/UserSettingsController.h b/lldb/include/lldb/Core/UserSettingsController.h
index a1ba2d32915c8..aa1040dd2eacf 100644
--- a/lldb/include/lldb/Core/UserSettingsController.h
+++ b/lldb/include/lldb/Core/UserSettingsController.h
@@ -64,7 +64,7 @@ class Properties {
void Apropos(llvm::StringRef keyword,
std::vector<const Property *> &matching_properties,
- std::vector<const Property *> &matching_property_prefixes) const;
+ std::vector<const Property *> &matching_property_paths) const;
// We sometimes need to introduce a setting to enable experimental features,
// but then we don't want the setting for these to cause errors when the
diff --git a/lldb/include/lldb/Interpreter/OptionValue.h b/lldb/include/lldb/Interpreter/OptionValue.h
index 9c992821251cb..b2b5d6bf6aeea 100644
--- a/lldb/include/lldb/Interpreter/OptionValue.h
+++ b/lldb/include/lldb/Interpreter/OptionValue.h
@@ -126,7 +126,9 @@ class OptionValue {
virtual llvm::StringRef GetName() const { return llvm::StringRef(); }
- virtual bool DumpQualifiedName(Stream &strm) const;
+ virtual bool DumpQualifiedName(
+ Stream &strm,
+ std::optional<Stream::HighlightSettings> highlight = std::nullopt) const;
// Subclasses should NOT override these functions as they use the above
// functions to implement functionality
diff --git a/lldb/include/lldb/Interpreter/OptionValueProperties.h b/lldb/include/lldb/Interpreter/OptionValueProperties.h
index d9f74c802c433..9ef4e670f95cd 100644
--- a/lldb/include/lldb/Interpreter/OptionValueProperties.h
+++ b/lldb/include/lldb/Interpreter/OptionValueProperties.h
@@ -59,7 +59,7 @@ class OptionValueProperties
void Apropos(llvm::StringRef keyword,
std::vector<const Property *> &matching_properties,
- std::vector<const Property *> &matching_property_prefixes) const;
+ std::vector<const Property *> &matching_property_paths) const;
void Initialize(const PropertyCollectionDefinition &setting_definitions);
diff --git a/lldb/include/lldb/Interpreter/Property.h b/lldb/include/lldb/Interpreter/Property.h
index 6e43c990fb366..e46db18a69f2b 100644
--- a/lldb/include/lldb/Interpreter/Property.h
+++ b/lldb/include/lldb/Interpreter/Property.h
@@ -60,7 +60,9 @@ class Property {
void Dump(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) const;
- bool DumpQualifiedName(Stream &strm) const;
+ bool DumpQualifiedName(
+ Stream &strm,
+ std::optional<Stream::HighlightSettings> highlight = std::nullopt) const;
void DumpDescription(
CommandInterpreter &interpreter, Stream &strm, uint32_t output_width,
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
index 8c594893c06e7..70cd828655af8 100644
--- a/lldb/source/Commands/CommandObjectApropos.cpp
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -23,7 +23,8 @@ using namespace lldb_private;
CommandObjectApropos::CommandObjectApropos(CommandInterpreter &interpreter)
: CommandObjectParsed(
interpreter, "apropos",
- "List debugger commands related to a word or subject.", nullptr) {
+ "List debugger commands and settings related to a word or subject.",
+ nullptr) {
AddSimpleArgumentList(eArgTypeSearchWord);
}
@@ -73,8 +74,8 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
// Find all the properties matching the search word.
size_t properties_max_len = 0;
std::vector<const Property *> properties;
- std::vector<const Property *> property_prefixes;
- GetDebugger().Apropos(search_word, properties, property_prefixes);
+ std::vector<const Property *> property_paths;
+ GetDebugger().Apropos(search_word, properties, property_paths);
for (const Property *prop : properties) {
StreamString qualified_name;
prop->DumpQualifiedName(qualified_name);
@@ -82,7 +83,7 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
std::max(properties_max_len, qualified_name.GetString().size());
}
- if (properties.empty() && property_prefixes.empty()) {
+ if (properties.empty() && property_paths.empty()) {
result.AppendMessageWithFormatv(
"No settings found pertaining to '{0}'. "
"Try 'settings show' to see a complete list of "
@@ -92,25 +93,24 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
} else {
return_status = eReturnStatusSuccessFinishResult;
- if (!property_prefixes.empty()) {
+ if (!property_paths.empty()) {
result.AppendMessageWithFormatv(
- "\nThe following settings prefixes may relate to '{0}': \n\n",
+ "\nThe following settings paths may relate to '{0}': \n\n",
search_word);
auto &out_strm = result.GetOutputStream();
out_strm.IndentMore();
- for (auto prefix : property_prefixes) {
+ for (auto path : property_paths) {
StreamString qual_name_strm;
- // TODO: highlight!!!!
- if (prefix->DumpQualifiedName(qual_name_strm)) {
+ if (path->DumpQualifiedName(qual_name_strm, highlight)) {
result.GetOutputStream().Indent();
result.GetOutputStream() << qual_name_strm.GetString() << '\n';
}
}
out_strm.IndentLess();
- result.AppendMessageWithFormatv(
- "\n(use 'settings list' to show settings with a given prefix)");
+ result.AppendMessageWithFormatv("\n(use 'settings list <path>' to "
+ "show settings with a given path)");
}
if (!properties.empty()) {
diff --git a/lldb/source/Core/UserSettingsController.cpp b/lldb/source/Core/UserSettingsController.cpp
index c7c33b947d1ab..3806cbbc9d84e 100644
--- a/lldb/source/Core/UserSettingsController.cpp
+++ b/lldb/source/Core/UserSettingsController.cpp
@@ -77,9 +77,9 @@ Status Properties::DumpPropertyValue(const ExecutionContext *exe_ctx,
void Properties::Apropos(
llvm::StringRef keyword, std::vector<const Property *> &matching_properties,
- std::vector<const Property *> &matching_property_prefixes) const {
+ std::vector<const Property *> &matching_property_paths) const {
m_collection_sp->Apropos(keyword, matching_properties,
- matching_property_prefixes);
+ matching_property_paths);
}
llvm::StringRef Properties::GetExperimentalSettingsName() {
diff --git a/lldb/source/Interpreter/OptionValue.cpp b/lldb/source/Interpreter/OptionValue.cpp
index aa118107f27c5..3ae4d7781e192 100644
--- a/lldb/source/Interpreter/OptionValue.cpp
+++ b/lldb/source/Interpreter/OptionValue.cpp
@@ -579,11 +579,12 @@ lldb::OptionValueSP OptionValue::CreateValueFromCStringForTypeMask(
return value_sp;
}
-bool OptionValue::DumpQualifiedName(Stream &strm) const {
+bool OptionValue::DumpQualifiedName(
+ Stream &strm, std::optional<Stream::HighlightSettings> highlight) const {
bool dumped_something = false;
lldb::OptionValueSP m_parent_sp(m_parent_wp.lock());
if (m_parent_sp) {
- if (m_parent_sp->DumpQualifiedName(strm))
+ if (m_parent_sp->DumpQualifiedName(strm, highlight))
dumped_something = true;
}
llvm::StringRef name(GetName());
@@ -592,7 +593,7 @@ bool OptionValue::DumpQualifiedName(Stream &strm) const {
strm.PutChar('.');
else
dumped_something = true;
- strm << name;
+ strm.PutCStringColorHighlighted(name, highlight);
}
return dumped_something;
}
diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp
index 3b0cdd453b0bc..bdd96548a0e14 100644
--- a/lldb/source/Interpreter/OptionValueProperties.cpp
+++ b/lldb/source/Interpreter/OptionValueProperties.cpp
@@ -464,7 +464,7 @@ void OptionValueProperties::DumpAllDescriptions(CommandInterpreter &interpreter,
void OptionValueProperties::Apropos(
llvm::StringRef keyword, std::vector<const Property *> &matching_properties,
- std::vector<const Property *> &matching_property_prefixes) const {
+ std::vector<const Property *> &matching_property_paths) const {
const size_t num_properties = m_properties.size();
for (size_t i = 0; i < num_properties; ++i) {
const Property *property = ProtectedGetPropertyAtIndex(i);
@@ -475,7 +475,7 @@ void OptionValueProperties::Apropos(
property->GetValue()->GetAsProperties();
if (properties)
properties->Apropos(keyword, matching_properties,
- matching_property_prefixes);
+ matching_property_paths);
bool matched = false;
@@ -491,7 +491,7 @@ void OptionValueProperties::Apropos(
continue;
if (properties) {
- matching_property_prefixes.push_back(property);
+ matching_property_paths.push_back(property);
} else {
matching_properties.push_back(property);
}
diff --git a/lldb/source/Interpreter/Property.cpp b/lldb/source/Interpreter/Property.cpp
index 7684e193106da..3fb64335dd9ff 100644
--- a/lldb/source/Interpreter/Property.cpp
+++ b/lldb/source/Interpreter/Property.cpp
@@ -234,14 +234,15 @@ Property::Property(llvm::StringRef name, llvm::StringRef desc, bool is_global,
: m_name(name), m_description(desc), m_value_sp(value_sp),
m_is_global(is_global) {}
-bool Property::DumpQualifiedName(Stream &strm) const {
+bool Property::DumpQualifiedName(
+ Stream &strm, std::optional<Stream::HighlightSettings> highlight) const {
if (!m_name.empty()) {
bool has_sub_properties = static_cast<bool>(m_value_sp->GetAsProperties());
- bool dumped_something = m_value_sp->DumpQualifiedName(strm);
+ bool dumped_something = m_value_sp->DumpQualifiedName(strm, highlight);
if (!has_sub_properties) {
if (dumped_something)
strm.PutChar('.');
- strm << m_name;
+ strm.PutCStringColorHighlighted(m_name, highlight);
}
return true;
}
diff --git a/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py b/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
index 73dad81c958a9..cfeb75a941bfe 100644
--- a/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
+++ b/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
@@ -47,12 +47,33 @@ def test_apropos_highlights_matches(self):
)
self.expect_prompt()
- self.child.sendline("apropos disass")
- # Check command name highlighting.
- self.child.expect_exact(ansi_green + "disass" + ansi_reset + "emble")
- # Check settings name highlighting.
- self.child.expect_exact(ansi_green + "disass" + ansi_reset + "embly-format")
+ self.child.sendline("apropos plug")
+ # Apropos should highlight in:
+ # Command names.
+ self.child.expect_exact(ansi_green + "plug" + ansi_reset + "in list")
+ # Command descriptions.
+ self.child.expect_exact(
+ "Report info about registered LLDB "
+ + ansi_green
+ + "plug"
+ + ansi_reset
+ + "ins."
+ )
+ # Settings paths.
+ self.child.expect_exact(
+ "platform." + ansi_green + "plug" + ansi_reset + "in.remote-android"
+ )
+ # Settings names.
+ self.child.expect_exact(
+ ansi_green
+ + "plug"
+ + ansi_reset
+ + "in.structured-data.darwin-log.auto-enable-options"
+ )
+ # Settings descriptions.
+ self.child.expect_exact("'" + ansi_green + "plug" + ansi_reset + "in")
self.expect_prompt()
+
self.quit()
@skipIfAsan
diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py
index 5035a3f23632d..02da8646349ba 100644
--- a/lldb/test/API/commands/settings/TestSettings.py
+++ b/lldb/test/API/commands/settings/TestSettings.py
@@ -26,13 +26,14 @@ def test_apropos_should_also_search_settings_description(self):
],
)
- def test_apropos_searches_settings_prefixes(self):
- """Test that 'apropos' command searches the prefixes of the qualified names."""
+ def test_apropos_searches_settings_paths(self):
+ """Test that 'apropos' command searches the components of the paths of
+ settings."""
self.expect(
"apropos 'qemu-user'",
substrs=[
- "The following settings prefixes may relate to 'qemu-user':\n"
+ "The following settings paths may relate to 'qemu-user':\n"
" platform.plugin.qemu-user\n"
"\n"
],
>From 65a480b278b035865c7fe66249fbfe695eaeeb44 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 5 May 2026 12:43:34 +0000
Subject: [PATCH 08/11] fix test
---
lldb/test/API/python_api/file_handle/TestFileHandle.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lldb/test/API/python_api/file_handle/TestFileHandle.py b/lldb/test/API/python_api/file_handle/TestFileHandle.py
index eba758f5a5d28..a0e66199d3f54 100644
--- a/lldb/test/API/python_api/file_handle/TestFileHandle.py
+++ b/lldb/test/API/python_api/file_handle/TestFileHandle.py
@@ -869,4 +869,6 @@ def test_set_sbstream(self):
with open(self.out_filename, "r") as f:
output = f.read()
self.assertIn("Show a list of all debugger commands", output)
- self.assertIn("List debugger commands related to a word", output)
+ self.assertIn(
+ "List debugger commands and settings related to a word", output
+ )
>From 7c425a7f03c7ee6360bcd45223fbbf84db98735e Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 5 May 2026 12:45:58 +0000
Subject: [PATCH 09/11] stray newline
---
.../API/commands/apropos/formatting/TestAproposFormatting.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py b/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
index cfeb75a941bfe..b9a8f52dbdc16 100644
--- a/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
+++ b/lldb/test/API/commands/apropos/formatting/TestAproposFormatting.py
@@ -73,7 +73,6 @@ def test_apropos_highlights_matches(self):
# Settings descriptions.
self.child.expect_exact("'" + ansi_green + "plug" + ansi_reset + "in")
self.expect_prompt()
-
self.quit()
@skipIfAsan
>From ff740e629c26c43464029d748a0b546d5c0e5362 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 5 May 2026 12:49:37 +0000
Subject: [PATCH 10/11] release notes
---
llvm/docs/ReleaseNotes.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index f315cb4dbaa0f..0fce0350f1d90 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -243,7 +243,10 @@ Makes programs 10x faster by doing Special New Thing.
* Breakpoint commands now accept `.` to refer to the location(s) at which the current thread is stopped. For
example, `breakpoint disable .` disables the just-hit breakpoint location. Another usage is to automate a
command to run at the current location: `breakpoint command add -o 'p my_var' .`.
-* The `apropos` command now highlights matching keywords in its output when color is enabled.
+* The `apropos` command now:
+ * Highlights matching keywords in its output when color is enabled.
+ * Searches the components of settings paths. For example `apropos qemu-user` will now
+ show `platform.plugin.qemu-user` as one of the results.
#### Deprecated APIs
>From c5f761db3021accae2c52fe009190e40c4b0f15f Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 5 May 2026 12:52:05 +0000
Subject: [PATCH 11/11] formatting
---
lldb/source/Commands/CommandObjectApropos.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
index 70cd828655af8..5f8719f6b5b8f 100644
--- a/lldb/source/Commands/CommandObjectApropos.cpp
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -121,7 +121,8 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
const bool dump_qualified_name = true;
for (auto property : properties)
property->DumpDescription(m_interpreter, result.GetOutputStream(),
- properties_max_len, dump_qualified_name, highlight);
+ properties_max_len, dump_qualified_name,
+ highlight);
}
}
result.SetStatus(return_status);
More information about the lldb-commits
mailing list