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

PR: Make Pygments to work correctly with QSyntaxHighlighter #3491

Merged
merged 9 commits into from
Jun 16, 2017

Conversation

ccordoba12
Copy link
Member

@ccordoba12 ccordoba12 commented Oct 2, 2016

Fixes #2122


Context:

  • The purpose of this PR is to finish @randyheydon's work started here: https://bitbucket.org/spyder-ide/spyderlib/pull-requests/103/
  • Right now we use Pygments to get tokens (and then highlight them) in a line by line basis. However, that's not how Pygments really works: Pygments needs to tokenize the whole file to correctly identify comments, strings, classes, etc.
  • This is why, for instance, multi-line comments in CSS files are not highlighted correctly in Spyder right now.
  • So we need to pass Pygments the entire file (instead of the current line) for tokenization, but in a way that doesn't introduce visible lags when working with big files (i.e. files with more than 1000 lines of code). @randyheydon already did the first part, and @goanpeca have done the second one.

TODO:

  • Move Pygments tokenization to a thread
  • Only apply it when the user stops typing

@ccordoba12 ccordoba12 added this to the v3.1 milestone Oct 2, 2016
@ccordoba12
Copy link
Member Author

Note to self: This could work for task 2:

https://wiki.qt.io/Delay_action_to_wait_for_user_interaction

@ccordoba12
Copy link
Member Author

Also see this for how much to wait to decide if a user has stopped typing:

http://ux.stackexchange.com/a/38545

@ccordoba12 ccordoba12 changed the base branch from master to 3.x October 4, 2016 00:36
@goanpeca
Copy link
Member

goanpeca commented Oct 4, 2016

@ccordoba12 could you provide some context on the description?

@ccordoba12
Copy link
Member Author

@goanpeca, sorry for being so brief :-) I updated the description to be more informative.

@randyheydon
Copy link
Contributor

Thanks for carrying this on @ccordoba12. I don't think I'll have a chance to help with this, but I would like to make a quick note. The best way to fix this, I think, would be to change Pygments to support incremental lexing. In the past, I believed they would not accept such a change, since it's outside of their scope. However, I've since noticed that they have the same problem with the -s (streaming) option to the pygmentize script. It currently does the same thing as Spyder, by highlighting each line individually. Therefore, it should be possible to change Pygments to create an incremental highlighting mode that could be used by both pygments -s and Spyder.

I haven't looked into it too much, but I imagine this would be done with a new or modified method that takes the current lexer state as an argument, and includes the final lexer state as part of the returned data. That way, you could parse a line based on previous state, highlight that line, then parse the next line with the new state. Some of the individual language parsers would also need to be modified so that they split multi-line constructs into shorter constructs with intermediate states.

@goanpeca goanpeca changed the title Make Pygments work correctly with QSyntaxHighlighter PR: Make Pygments work correctly with QSyntaxHighlighter Oct 26, 2016
@ccordoba12 ccordoba12 modified the milestones: v3.1, v3.1.1 Jan 6, 2017
@ccordoba12 ccordoba12 modified the milestones: v3.1.1, v3.1.2, v3.1.3 Jan 18, 2017
@ccordoba12 ccordoba12 modified the milestones: v3.1.3, v3.2 Jan 27, 2017
@ccordoba12 ccordoba12 modified the milestones: v3.2, v3.3 Feb 14, 2017
@goanpeca
Copy link
Member

goanpeca commented Jun 1, 2017

@ccordoba12 what is the status of this? I could add the generic threaded worker from the work I will add for the spyder-anaconda plugin. We could then use that worker to run things like what we want to accomplish here?

@jitseniesen
Copy link
Member

@goanpeca Regarding this "generic threaded worker" you are working on, does the worker run on a different thread in the same process, or a different process?

I'm asking because for the unittest plugin, I need a worker in a different process which can continuously communicate the results back to spyder, so that the display can be updated in real time instead of having to wait until all tests are run.

@goanpeca
Copy link
Member

goanpeca commented Jun 1, 2017

@jitseniesen yes, I will have a generic worker for running python stuff (a method/func? that may be a long process) and a specific set of workers for a couple of tasks. A QProcess worker (that effectively runs a separate process and periodically signals (worker, stdout, stderr) so you can use it as well. I will add this code as generic stuff on spyder so any plugin can use this workers for long running processes.

@jitseniesen
Copy link
Member

Excellent, I'll wait for it to appear so that I can use it instead of making my own. Perhaps we can also make the introspection stuff use your generic worker.

@goanpeca
Copy link
Member

goanpeca commented Jun 2, 2017

Perhaps we can also make the introspection stuff use your generic worker.

We are planning on using https://github.com/Microsoft/language-server-protocol, which already provides a generic framework for what we need, plus there is already a python implementation plus many other languages, so we would get completion, linting for free for all those languages

self._is_finished = True


class ProcessWorker(QObject):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jitseniesen this is the idea for the process worker, maybe you could take a look and see if it fits your needs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@goanpeca Yes, I think that will work for me.

@ccordoba12
Copy link
Member Author

@goanpeca, how is this going? We need to merge this one as soon as we can, please.

@@ -1074,33 +1075,81 @@ def __init__(self, parent, font=None, color_scheme=None):
# Load Pygments' Lexer
if self._lang_name is not None:
self._lexer = get_lexer_by_name(self._lang_name)



Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove two blanks here and just leave one.

self._allow_highlight = True

def make_charlist(self):
""""""
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing docstring.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing!


def make_charlist(self):
""""""
def test_output(worker, output, error):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this function called test_output? It would seem to imply that it's only used for tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing!

# Highlight using Pygments highlighter timer
self.timer_syntax_highlight = QTimer(self)
self.timer_syntax_highlight.setSingleShot(True)
self.timer_syntax_highlight.setInterval(300)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to explain this 300 here.

@@ -1052,6 +1052,7 @@ class PygmentsSH(BaseSH):
# Store the language name and a ref to the lexer
_lang_name = None
_lexer = None
_charlist = []
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be needed because _charlist is also initialized in __init__ below.

# parsing
self._worker_manager = WorkerManager()

# Store the format for all the tokens after pygments parsing
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pygments -> Pygments

self._charlist = []

# Flag variable to avoid unnecessary highlights if the worker has not
# yet finish processing
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finish -> finished

@ccordoba12
Copy link
Member Author

@goanpeca, do you want me to finish this one?

@goanpeca
Copy link
Member

goanpeca commented Jun 15, 2017

Oops I did not see the comments, giv me a sec


@ccordoba12 done!

@ccordoba12
Copy link
Member Author

Thanks a lot for helping me to finish this one @goanpeca!! Great work!

@ccordoba12 ccordoba12 changed the title PR: Make Pygments work correctly with QSyntaxHighlighter PR: Make Pygments to work correctly with QSyntaxHighlighter Jun 16, 2017
@ccordoba12 ccordoba12 merged commit d5bddbe into spyder-ide:3.x Jun 16, 2017
@ccordoba12 ccordoba12 deleted the improve-pygments branch June 16, 2017 03:38
ccordoba12 added a commit that referenced this pull request Jun 16, 2017
Fixes #2122

* Conflicts:
- spyder/utils/syntaxhighlighters.py
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.

4 participants