jupyter / qtconsole

Jupyter Qt Console
https://qtconsole.readthedocs.io/en/stable/
BSD 3-Clause "New" or "Revised" License
418 stars 200 forks source link

Style elements in stylesheet do not get applied #334

Open Jeitan opened 5 years ago

Jeitan commented 5 years ago

I am trying to apply a custom style to Jupyter QtConsole, and am finding that I can influence the style using one of Pygments' builtin styles(jupyter qtconsole --style=native), and I can influence the Qt and prompts (.in-prompt, etc.) using a stylesheet, but I cannot influence the syntax style using a stylesheet. In particular, I have a file I obtained by doing pygmentize -S native -f html > native.css, but then when I try jupyter qtconsole --stylesheet=native.css, nothing happens to the style. It also appears to not work when specified in c.JupyterQtConsoleApp.stylesheet in the config file (the Qt parts change, but the style parts don't). When I put it into c.JupyterWidget.style_sheet in the config, it actually makes qtconsole crash. I can't tell from the documentation why this doesn't work ... the config notes near the latter seem to indicate that all should be just fine.

I am trying to use some custom styles I like, and I must do it by config or by command line - I have no control over the installation so I cannot put a new style into Pygments' folder in site-packages.

The systems I actually work on are all offline, but it also appears not to work in the developer version I'm testing with from the most recent code, it says 4.5.0.dev0. Python 3.7.3, pyqt 5.9.2.

ccordoba12 commented 5 years ago

The feature probably doesn't work with a local style. You're welcome to submit a pull request to fix it.

Jeitan commented 5 years ago

Well, okay ... but could you clarify when one should using c.JupyterWidget.style_sheet, and why it crashes? This is the notes in an auto-generated config file with no changes:

## A CSS stylesheet. The stylesheet can contain classes for:
#      1. Qt: QPlainTextEdit, QFrame, QWidget, etc
#      2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
#      3. QtConsole: .error, .in-prompt, .out-prompt, etc
#c.JupyterWidget.style_sheet = ''

If that's wrong, it should probably be changed. I also don't understand what the difference is between the two specifications in the config in the first place.

ccordoba12 commented 5 years ago

@dalthviz, could you provide a little help here?

Jeitan commented 5 years ago

So I have done some digging, and I admit to still being thoroughly turned around regarding where/what object/what initialization all of this is going on in, but think I've discovered at least one thing that looks inconsistent, but also something really weird.

In qtconsoleapp.py, in the init_colors method of JupyterQtConsoleApp, it pulls style sheets from two sources: a) self.stylesheet and b) self.config.JupyterWidget.style_sheet. From some debugging outputs, I have learned that the command line specification --stylesheet= goes into (a), the config line c.JupyterQtConsoleApp.stylesheet also goes into (a), and the config line c.JupyterWidget.style_sheet goes into (b). (So it is (b) that makes it crash ... it opens fine but quits as soon as I type a single key).

There is a discrepancy with how (a) and (b) are handled, because toward the end of the function, the file path in (a) actually gets opened and read, with the resulting string going into a variable sheet, which is then assigned to widget.style_sheet (and I think widget is a highlighter object?). If both (a) and (b) are given, this overwrites whatever was in (b). However, if there is nothing in (a) but we do have (b), (b) gets assigned to widget.style_sheet without being read first - so when (a) is active a string with CSS in it is being used, if (b) is active it's just a file path. I couldn't tell if that is handled gracefully further down the object hierarchy?

I thought at first that might be why it dies when I try to use c.JupyterWidget.style_sheet. However, I modified the code (I set up a qtdev environment as per the guidelines) and added the same read functionality, and have verified that the exact same string (containing CSS) is being assigned to widget.style_sheet, but when I use the config it still dies...

I also noted that perhaps it would fix the missing syntax highlighting (even for option (a)) if widget._syntax_style_changed() were also called in the if sheet: block, but that had no apparent effect.

I think this may be above my level of familiarity, because at this point I'm completely stumped.

dalthviz commented 5 years ago

@Jeitan sorry for the delay to respond. After reviewing this, as far as I can tell, the widget you found is a JupyterWidget instance. In the past, we used the style_sheet attribute (which should be a string like the ones in the default template at qtconsole/styles.py) in PR #217 to change the color scheme of the console. On the other hand you have the syntax_style attribute of the JupyterWidget which is the the pygments Style subclass that will be used for the highligther of the JupyterWidget instance. In spyder-ide/spyder#4000 we implemented a way to create the Style subclass on the fly but using the config of color schemes available in Spyder as a base to build it. Hope this give you some inside of what's going on with the stylesheet setting.

Jeitan commented 5 years ago

@dalthviz Thanks for the explanation! I perused the PRs you mentioned, and now I can kind of see how things ended up. If I have some free time at some point I might try to see if I can get some sort of local style input working ... maybe by looking at what Spyder does.

vivekjoshy commented 5 years ago

@dalthviz I have the same issue, but after going through https://github.com/jupyter/qtconsole/pull/217 it appears to be the case that syntax_style is hard coded to the set of builtin pygment styles. Am I right about my analysis? (A temporary fix was to register a plugin for pygments)

dalthviz commented 5 years ago

@daegontaven awesome! As far as I remember what I did in that PR was to create some methods to set the syntax_style using the available pygment styles via the GUI, so it make sense that you can add custom syntax styles registring plugins for pygments. Also, I think that the PR more than hardcoding the syntax_style lets you handle the syntax_style attribute of the console changing it using the available pygments styles, althougth if you have a valid custom Style subclass you could potentialy set it with set_syntax_style at qtconsole/mainwindow.py. Maybe what we need here is to provide a way to set programatically a class for syntax_style using the info of style provided with the stylesheet argument (something that probably needs the dynamic creation of a Style subclass in a similar way as in spyder-ide/spyder#4000 and more specifically spyder/utils/ipython/style.py).

Jeitan commented 5 years ago

Some of that was a bit hard to follow for me (sorry), but I'm all for that last sentence! At some point in the past I looked into a pygments plugin (since I'm not admin and can't modify the pygments/styles directory), but I got pretty confused pretty quickly since I've never had the need to use setuptools. I'm not a programmer, merely a scientist who programs :P. So having a stylesheet-type input would be lovely!

vivekjoshy commented 5 years ago

@dalthviz My use case is specifically to set syntax style from RichJupyterWidget in another application.

jupyter_widget = RichJupyterWidget()
jupyter_widget.style_sheet = get_theme_contents(
    "dracula",
    "jupyter.css"
)  # Custom method that grabs a stylesheet css file
jupyter_widget.syntax_style = "dracula"

The above works in so far as I register a pygments plugin in advance. It does not work if i try to set a pygments Style class for jupyter_widget.syntax_style since it only accepts strings as seen here: https://github.com/jupyter/qtconsole/blob/b2fa483b06972403de81550b04318f5554a066ba/qtconsole/jupyter_widget.py#L90-L95

There is no way to set it from RichJupyterWidget. That would be a nice feature and I assume it would also solve the issue @Jeitan is facing.

dalthviz commented 5 years ago

@daegontaven you are right, reviewing more in deep what we did for Spyder, we reimplemented the method _syntax_style_changed from the RichJupyterWidget to set the highlighter style (_highlighter._style) to the class we generated dynamically. Maybe adding a way to set the style of the highlighter is what we need here :)

NightMachinery commented 3 years ago

(Trying to confirm my understanding)

We can not use local CSS files with qtconsole? Would it work if I upload the file to an HTTP server and use --stylesheet=https://.../theme.css?

ccordoba12 commented 3 years ago

Right now it doesn't work locally nor via web.