This is an archive of the discontinued LLVM Phabricator instance.

Add "command multiword add" and the ability to add script commands into a user multiword hierarchy
ClosedPublic

Authored by jingham on Sep 22 2021, 5:30 PM.

Details

Summary

One of the ways that we organize all the functionality provided by lldb is to use a hierarchical command structure, with nested commands. That means that when you first look at lldb, you see an organized set of commands mirroring the basic constructs in a debugger. Then we use aliases to make the most commonly used commands available in a couple of keystrokes. But when you start adding user commands, since they have to be root commands, you quickly overwhelm this orderly setup. To fix this problem, I'm adding the ability for users who add commands to also nest them in a sensible hierarchy.

This change keeps the "built-in" and the "user added" command hierarchies separate, you can't add user commands or multiword subtrees into the builtin commands. I think it would be too confusing if we started having user commands sprinkled among the built-in commands. I also don't allow you to add aliases into multiword command trees. The whole point of aliases is to make something available at the top level, so this didn't seem to make sense.

I apologize in advance for the size of the patch, but there really wasn't anything testable up till it was actually working, which is pretty much this patch.

Diff Detail

Event Timeline

jingham created this revision.Sep 22 2021, 5:30 PM
jingham requested review of this revision.Sep 22 2021, 5:30 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 22 2021, 5:30 PM

Note, I didn't do anything on the SB API side. We don't have a way to add commands of any sort through the API's, so we would have to do all that work along with adding multiword support, which is certainly fodder for a separate patch.

I also didn't mirror "command script list" - I'm not sure how useful that is and anyway, that's an orthogonal piece of work, and this patch is big enough already.

The other slightly awkward choice I made was to have all the commands that take command paths (e.g. "command script add" and "command multiword add") take them with each component of the path as a separate argument. We have an argument type for commands, but the problem with that is then you'd have to make the path a single word, i.e.:

(lldb) command script add "foo bar baz"

which would I think be annoying. It made writing the completer a little trickier, but I think it's worth it to be able to write:

(lldb) command script add foo bar baz

If we ever need to write a command that has arguments that are some command paths and some other types of arguments, we'd have to have single argument paths, but I think it would be better to use options to avoid having to do that.

jingham added inline comments.Sep 22 2021, 6:12 PM
lldb/source/Commands/CommandCompletions.cpp
802

Second "options" should be "arguments". I'll fix that with any other edits as they come along.

I did a quick pass as I was reading through the patch to understand it. I'll do another one tomorrow.

lldb/include/lldb/Interpreter/CommandCompletions.h
156–159
lldb/include/lldb/Interpreter/CommandInterpreter.h
235

Really these should all be Doxygen comments (//<) but I know you're just adding values.

309–311

Please clang-format before landing.

324

Copy/paste?

lldb/include/lldb/Interpreter/CommandObject.h
198

Maybe say "built-in" command or "non user-defined" command?

lldb/source/Commands/CommandCompletions.cpp
811–813

I'm surprised this works. Don't the indexes shift when one's deleted? I assumed that's why you're sorting them.

lldb/source/Commands/CommandObjectCommands.cpp
1576

This should probably be lowercase to be consistent with the other error strings.

1744

Lowercase?

1934

All the previous errors started with a lowercase letter. I don't have a preference, but we should be consistent.

lldb/source/Commands/CommandObjectMultiword.cpp
98

In line with the direction of preferring llvm::Error over lldb_private::Status, I think these two functions would be good candidates to return llvm::Errors instead. We can always convert them to a Status up the chain.

101–103

This is not going to compile in a non-assert build. You'll want to inline the if-check in the assert.

lldb/source/Interpreter/CommandInterpreter.cpp
900

Similar to my previous comment, this could be an expected instead of using a Status as an output argument.

The changes look fine from a quick read. See inline comments

lldb/source/Commands/CommandObjectCommands.cpp
1852

can't this just be "command add" instead of "command multiword add"?

1994

Could we just modify the existing "command delete" instead of adding a new command here?

2126–2127

"multiword" makes sense to us LLDB software folks, not sure it will resonate with general public. See comments above about maybe doing "command add" and then modifying "command delete" to also handle multiword duties

jingham added a comment.EditedSep 29 2021, 9:54 AM

The changes look fine from a quick read. See inline comments

The command add/command delete situation is a little fractured. We currently have:

command alias/command unalias - Handles aliases to commands
command regex/command delete - Adds and deletes regex commands
command script add/command script delete

It would be weird for "command delete" to delete regex and multiword commands but not script commands and not aliases.

We could centralize everything to "command add --multiword", "command add --script" etc. Then it would make sense to delete everything in command delete as well. But that might break a bunch of people's .lldbinit's etc. And anyway, I don't have time to do all that right now.

Moreover, I actually think that deleting a multiword command as a separate gesture isn't a bad idea. Deleting a script command deletes one thing and can be easily undone (by re-adding that one command). Deleting a multiword command can potentially wipe out a whole hierarchy that you had built up. It would be really annoying to have:

(lldb) command delete foo bar

where I forgot to put "baz" on the end would delete baz and everything else in the container. You could add --force to delete, but I'm not sure that's a better interface.

If somebody can think of a more apt name than "multiword" I'm not wedded to that name. "container" might be okay?

jingham updated this revision to Diff 376406.Sep 30 2021, 6:03 PM
jingham marked an inline comment as done.

Addressed Jonas' review comments.

jingham marked 9 inline comments as done.Sep 30 2021, 6:06 PM

Addresses Jonas' first round of comments.

lldb/source/Commands/CommandCompletions.cpp
811–813

Why wouldn't it?

The delete starts with the greatest index, so each time you delete an entry it shuffles the ones above it down, but it doesn't reshuffle the ones below it. Since all the remaining indices are lower than the one you just deleted, they are all still pointing to the elements you intend to remove.

lldb/source/Commands/CommandObjectMultiword.cpp
101–103

The other places this check is done use lldbassert (in CommandInterpreter.h). I'll switch to that for consistency's sake.

lldb/source/Interpreter/CommandInterpreter.cpp
900

This one can't be an expected. It returns nullptr in two cases:

  1. When the path was wrong, in which case there was an error
  2. When the path is a top-level multiword, in which case there's no error

This is documented in its help.

We wouldn't have to do it this way if we had made a "root level" multiword command that we add all the top-level commands to, because then the top level commands would have a container, but we didn't and they don't. So I have to do it this way.

jingham updated this revision to Diff 376410.Sep 30 2021, 6:37 PM

My brain wants llvm::Error to be false when there's an error, (probably because false is the bad state.) Fix a case where I didn't catch myself...

A few more nits as I was reading through the code, but this generally LGTM.

lldb/source/Commands/CommandCompletions.cpp
811–813

Got it, I got the direction wrong.

lldb/source/Commands/CommandObjectCommands.cpp
2028

This method still has some inconsistencies in capitalization.

lldb/source/Commands/CommandObjectMultiword.cpp
34–35
53–67
111–114
120–128

This inline diff looks more confusing than anything, but basically I just switched the errors around (instead of the current fall-through) and return the error immediately.

lldb/source/Interpreter/CommandInterpreter.cpp
1259–1262
1367–1368
jingham updated this revision to Diff 379145.Oct 12 2021, 12:25 PM
jingham marked an inline comment as done.

I changed the command name from "command multiword" to "command container".

Greg noted that "multiword" is what we used for these but it's actually not a great description of what you are adding. "Command Containers" seems closer. It doesn't also reflect the fact that you can nest containers in containers, but I think that's not going to confuse anyone.

That's the best name I could come up with, but I do think it's better than "command multiword".

I also addressed Jonas' comments.

lldb/source/Commands/CommandObjectMultiword.cpp
120–128

This isn't an early return vrs. not early return thing, since the if's are just deciding which error to print, then we return directly if there was an error.

TTTT, I like my version better. Your version hides the error message in the middle of two copies of all the llvm::createStringError goo, which makes it much harder to read, IMO.

This revision was not accepted when it landed; it landed in state Needs Review.Oct 18 2021, 3:29 PM
This revision was automatically updated to reflect the committed changes.