Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DOM inspector devtools #2896

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Add DOM inspector devtools #2896

wants to merge 1 commit into from

Conversation

1j01
Copy link
Contributor

@1j01 1j01 commented Jul 6, 2023

  • Docstrings on all new or modified functions / classes
  • Updated documentation
  • Updated CHANGELOG.md (where appropriate)

This PR adds a DOM inspector panel, which toggles with F12 when running with textual run --dev

dom_inspector_demo.webm

Features

  • Inspect Element lets you point and click to pick any widget. Works just like in the browser.
  • DOM tree, which highlights elements as you mouse over them.
  • Properties Tree, to explore all the data associated with a widget.
    • Supports virtually all Python types
    • For performance, not all properties are shown at once in large objects, but can be shown by clicking the ellipsis.
  • CSS tab — lists rule sets that apply, and inline styles.
    • Color values are highlighted.
    • Inline styles can be edited.
    • Each ruleset links to the source code where it's defined.
    • Individual inline styles link to the last place they were set. This looks at the callstack and ignores framework-level style setting helpers.
  • Keys tab — display key bindings in a table, including from parent widgets.
  • Events tab which shows messages that can be posted by the selected node, as well as which nodes further up in the DOM handle each message type.
    • Listed message handlers link to the DOM node in the DOM tree view.
    • Listed message handlers and message classes link to the source code where they're defined.
    • This currently only shows Message classes exposed as class variables on the node's class / superclasses, and not built-in events or other messages not exposed in that way.
  • Layout can be resized horizontally and vertically.
  • When hovering an element, the highlight also highlights the clipped/occluded region, which is very useful for seeing why an element is invisible, in many cases.
  • When clicking a source code link, it heuristically tries to open your preferred editor, based on what processes are running, but this can be configured with an environment variable. This feature uses MIT licensed code ported from Create React App.

Questions

  • Should the F12 binding use priority?
  • The instrumentation used to record stack traces incurs significant overhead, especially at app startup. How should it be made optional? An env var? A CLI flag? A persisted GUI option?
  • Instrumentation was a good way to prototype this inspector in the context of my project, but would it be better to make the library code explicitly call out to the inspector instead? What would be the performance of this? (It seems like it could give better performance while active, but it might be marginally worse for the case that it's disabled.)
  • For a proof of concept I added action_toggle_inspector to the app instance in an ad-hoc way, but I'm guessing it would be better to define it normally as a method. But what should it do if dev tools aren't enabled (maybe not even installed)? Raise an error, or do nothing?
  • The env var to specify a particular editor to open when clicking source code links is currently TEXTUAL_EDITOR, but this may be a bit confusing since it sounds like the opposite of VISUAL, a common env var for specifying a graphical text editor, to be favored over EDITOR.
    • REACT_EDITOR is what Create React App uses, and I thought about leaving it to use this, in the hopes that you may have set it to your preferred editor, but you may not prefer the same editor for both sorts of projects, so I think it's better to create an explicit separation.
    • TEXTUAL_FRAMEWORK_EDITOR would be clearer but quite verbose
    • TEXTUAL_DEV_EDITOR might be a good middle ground
  • Should this be broken up into more files?
  • Should I remove the license header?

Todo

In addition to todo comments in the code, I have an external todo list, which I could share, but I'd want to clean it up first.
In short:

  • There are certainly some things which can be better implemented with changes to the library, like tracking of the path of a RuleSet, which I implemented by monkey-patching RuleSet.__init__, and using tracebacks to extract the path variable like it's a heist movie.
  • There's a potential memory leak with tracebacks. This should be easy to solve since it doesn't really need to store the tracebacks, just the information it extracts from them.
  • There are some bugs with double-acting clicks.
  • It could use a close button.
  • It would be nice if the inspector was isolated from regular queries and user CSS (like with the Shadow DOM in browsers), because right now for instance the dictionary example app crashes with TooManyMatches on query_one(Input) if you try to edit inline styles, and the calculator example app makes the "Inspect Element" button take up the entire inspector panel.

@willmcgugan
Copy link
Collaborator

Hi @1j01 This is objectively awesome.

We had planned to create a developer tools that would work much like this, but it would work over a websocket in a separate terminal.

I'm wondering then if this would be better done in an external package. We would be happy to update Textual to make it easier to integrate.

Regardless, this is amazing work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants