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
Syntax Highlighting #24
Comments
@clojj |
ok, will take a look at it |
btw, thinking about syntax highlighting Haskell... https://github.com/tonsky/FiraCode |
Nifty! I haven't seen that font before; I'm glad it just works like that! |
works like a charm ! (hope I did it the right way... am somewhat new to the Lens library) |
I have been thinking about tokenization. a) keep tokenization completely in sync with the event loop, running after each buffer change b) make it an async Action, like you suggested previously. This is tricky to get right because of possible async changes to the text buffer after tokenization finishes. Performance could be suboptimal because of 'double-checking' c) modify Rasa's eventloop, so that it controls the triggering of tokenization itself. For example, if there is no keypress after a configurable amount of time (say 300 ms), a 'timer' will trigger and call a registered tokenizer function. This call should be synchronous, so that any other keypress events will be dispatched after the tokenizer is finished. ...possible other strategies? Caching and other optimizations can help in all cases for sure. |
Okay I took a look over your current implementation; the shell looks good; I believe it's possible to get around the use of explicit MVars in the final implementation if you use doAsync; Here's a shell of my initial idea (hasn't been tested): data SyntaxHighlighter = SyntaxHighlighter
{ _isProcessing' :: Bool
}
makeLenses ''SyntaxHighligher
isProcessing :: HasBuffer b => Lens' b Bool
isProcessing = bufExt.isProcessing'
instance Default SyntaxHighlighter where
def = SyntaxHighlighter False
highlighter :: Action ()
highlighter = onBufferChanged startParse
startParse :: Action ()
startParse bufRef = bufDo bufRef $ do
processing <- use isProcessing
-- If there's already lexing taking place don't spawn another job.
unless processing $ do
isProcessing .= True
txt <- use text
-- The next part we can do asynchronously
liftAction $ doAsync $ asyncLex bufRef txt -- Run 'asyncLex' asyncronously
-- Everything in this function is done async; it returns the Action *describing* the next SYNCHRONOUS action which will
-- be run *eventually*
asyncLex :: BufRef -> YiString -> IO (Action ())
asyncLex bufRef oldText = do
tokens <- lexText txt -- This is the slow part; we don't need forkIO; doAsync handles that.
return (bufDo bufRef $ applyTokens txt tokens)
-- Everything in this function will *eventually* get pulled into the event loop and will be run synchronously thus
-- applying any changes. Things may have changed since 'asyncLex' ran.
applyTokens :: YiString -> [Token] -> BufAction ()
applyTokens oldText tokens = do
-- Set the styles even if the text is outdated; what we have is probably better than what's currently set anyways.
setStyles tokens
newText <- use text
isProcessing .= False
-- If the text when we're finished is different than the text when we started; start over again.
when (newText /= oldText) (liftAction startParse) Alternatively; it would certainly be possible to build in some way to 'cancel' async jobs (since we just use Control.Concurrent.Async for those) if that would help. With the example I provided we're guaranteed to keep making progress even if the user keeps typing though; worst case the highlighting gets a bit behind; but that's still much better than freezing the editor. The proper way to do this is incremental parsing; which incidentally some folks working on Yi have written a research paper on. Maybe we can integrate some of that knowledge as we go! I still have to give it a proper read yet. As an alternative to triggering via keypress we could build in an activity 'debouncer' like you suggest without too much difficulty. Roughly speaking we could have Rasa dispatch an Does any of that help?? Thanks for crunching away on this! |
Ok, I'll safe your suggestion definitly as a 'backup solution'. Actually I'm trying to get such an event in IO in my current experiments, it would sure make more sense to have this as a regular Rasa event. It'd be fantastic if you could prepare a branch for that (?) |
Yup; I can whip that up in the next few days 👍 |
Oh wow! cool stuff! It's a team effort 🤜 🤛 👌 Also @clojj I noticed you're not in the Gitter Chat; you're missing a few interesting conversations there; consider joining us 😁 |
Ok, I have to look into your doAsync proposal... it may have good performance. As for using MVars.. they are needed because there is a loop running inside About the other strategy ( |
Two things...
|
example with fold-debounce:
...works as designed! |
That's pretty cool; It looks like it'd be tricky to use the |
This is in Linux, running rasa inside a QTerminal (should run on all linux distros) with Fira Code and ligatures. Thanks for pulling #20 ...hopefully I can make progress on lexing soon. |
How can we standardize a useful representation of syntax highlighting usable across filetypes?
The text was updated successfully, but these errors were encountered: