Regex Highlight Node
Hi everyone! I really love Nodebox. But as a motion graphics artist with clients that don't always have a ton of extra time for lookdev and R&D, I don't often have a chance to use it as much as I'd like. But I run a side project called Workbench and another company called Element Supply Co. and during the holiday break I'm taking some time to build a new product that relies on generating a bunch of terminal UI, and Nodebox is perfect for that. However, I wanted to highlight some text—basically code highlighting—and I couldn't find a good way to do that in Nodebox. Note that this isn't going to work for variable width text, but I happen to be using monospaced text, so this solution works perfectly for me and maybe it can help you too, or perhaps you can find a way to improve upon it.
This is the basic python code for the node. It finds whatever regex you specify in the search for the node, and it applies it to strings/lists it's given. Where the search is found, it returns a list with the first string having the original text with spaces where the search terms are found and the second string having everything as spaces except for the search terms. In this way, you can split them out to two separate textpath nodes and color them differently or use different font weights.
I build the second string by checking each character between the new string and the original one. You can probably build a regex solution to get the opposite which is probably faster, but this is the route I took. I was originally using difflib but I realized that I couldn't get a string like I wanted easily enough and even if I could compare them, I couldn't keep only the differences the way I needed to.
import re
def highlight(list, search):
listA = re.sub(search, blank, list)
listB = ''
for i in range(len(list)):
if list[i] != ' ' and list[i] != listA[i]:
listB += list[i]
else:
listB += ' '
newList = [listA, listB]
return newList
def blank(matchobj):
blank = ''
for x in range(len(matchobj.group(0))):
blank += ' '
return blank
There might be a better way to return these lists. I'm newer to Python than I am to most other languages, and especially with Nodebox, so perhaps there's a better way. I tried to return these in a list of lists, but it didn't seemingly work out that way. I looked at some of John's code but couldn't figure out a solution to return what would essentially be an array with Index and two data points for each index. It seemed from the docs that that wasn't possible too so I didn't go too far in since I can do this with a take_every node and be done with it and keep a lot of flexibility in my solution. But if you have a better way to do it with less node spaghetti, I'm all ears!
Also, I'm using Aglet Mono in my example in case you're wondering. It's on Adobe Fonts. I didn't provide the text file I'm using in the more complicated example because you'd likely want to do something on your own anyway. This isn't even the final way I'm using it. It's just a test for me.
I think that's everything. Feel free to ask any questions. I'll be making more nodes in the future for sure. I do wish there was a better way to integrate them, but having to link a code library isn't a huge problem in the grand scheme of things.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
Support Staff 1 Posted by john on 28 Dec, 2021 02:07 AM
Hi Joe!
Thanks for sharing this! I am excited to see a new custom node and even MORE excited to hear that you may be sharing more of them.
Nodebox's very limited text presentation abilities are a known sore spot. Your node strikes me as a somewhat desperate solution, thought it should work well enough as long as you stick to monospaced fonts and take one line at a time.
An alternative approach would be to use my style text node, essentially a mini markup notation, available in my node library and described here:
http://support.nodebox.net/discussions/show-your-work/366-style-tex...
I use a tilde to indicate highlighting. If your code does not already use tildes you could simply replace all occurrences of WORD with ~WORD~. You could then use my arrange node to output blocks of text, even in non-monospaced fonts.
Your node reminded me of the power of RegEx expressions for Perl-like string munging. You could create nodes similar to your highlight node that were more general purpose and which could expose RegEx functionality in a Nodebox friendly way. I can see many possibilities!
I feel your pain trying to return results to NodeBox in various formats. There is basically NO documentation for how to do this and I've had to endure much trial by error to find techniques that work in my various custom nodes. The more custom nodes we have in this forum to use as examples, the greater our chance of finding ways to return things the way we want to.
Thanks again and welcome to the custom node biz. I look forward to seeing more goodies!
John
2 Posted by joe.s.clay on 31 Dec, 2021 07:54 PM
Thanks John!
Weird, I didn't get a notification for this. I've actually downloaded your nodes recently to check some things while I was building some of my designs, but I'll have to dig deeper when I get a chance—especially into that one! I'm glad to hear that I'm not alone with the trial and error. I will say this, it's still easier to make a custom node for Nodebox than most anything custom for After Effects, and I've been doing that for years!
As you noted, this particular node was definitely a specific thing for my use case, and indeed a desperate solution, but I have since made a few others that may have more broad appeal which I've attached here now.
And speaking of a broader use for RegEx, there's one node in here that basically replaces the functionality of the Contains node by exposing RegEx instead. I made it for another design I built for code highlighting that used Contains previously.
There are a few others that I found useful for my specific case, which may or may not be useful to others.
One is a weak version of your Treemap setup (which I need to look into more), but might have more useful appeal for things other than how I used it. It's called Subgrid for now. Subgrid is basically is a random number generator that will only return even integers and the number 1 from the range you provide.
Column is a quick network I was using that basically takes list input and makes a grid of the proper size so if you add any text to the grid, it just goes to the bottom rather than shifting the whole grid vertically as things are added.
Shifter was used where I had a bunch of random hex codes that I grabbed out of my terminal—basically for greeked UI "encrypted code"—and my examples were about 300 characters wide and in even columns, so I wrote this node to basically crop them into a list to make it less wide. Again, something useful to me, but maybe not to others. It's sort of like the Substring node, but it keeps all the data.
And finally there's Switcher, which again was useful to me, but may or may not be useful to anyone else. It grabs txt/csv files so I didn't include a working example in here because no one needs my random files, but basically I had a situation where I had 26 crash logs to bring in. I was going to make one big file with them all evenly spaced, but rather than have a thousand line text file—and have to make it—I decided to quickly write a node to go through the files like the Switch node. I was going to use a combo of a bunch of Switches but it took a few minutes to code a new node, so why not?
All of my text files were named similar to
Thread Crash 01.txt
so this node basically dumps the last 6 characters, keeps the last 4 characters, and throws them back together with whatever integer you put in the middle. It only goes to two digits because I don't want to meet the madman who has hundreds of text files to go through!That's all for now, but I'm sure that as I continue working on the product that I'm building, there will be more. We have a Patreon page where we put out files each month, and I've included the image we built for this month so you can see how this is starting to be used. The UI bits were all Nodebox.
Anyway, happy New Year and I'll be back with more in 2022!