I like to try various things out in my editor to see if they're useful. Most are interesting but not useful. On my guide to hexagons I use colors for the three hexagon axes (q, r, s). I thought it might be cool to do something similar in the text editor, for x and y:

Coloring variables by which axis they refer to

Type systems already do so much for us. A type system catches operations that should not be allowed, like sqrt("hello"). But primitive types tend to be tied to hardware formats like int32, double, char*. Some type systems work with the types humans think about instead of what machines think about. For example, a type system could catch an invalid operation like 3_meters + 5_grams. Or sql`SELECT * FROM ` + html`<img>`.

These kinds of systems are sometimes awkward to work with when you have to prove to the compiler that your code is correct. But what if they're just warnings in the editor and not compile errors? I implemented this using regular expressions and tree-sitter. I already was using tree-sitter to highlight specific keywords:

(tree-sitter-hl-add-patterns 'python
  [
   ["assert" "return" "raise" "finally" "continue" "try" "except"]
   @keyword.major
   ])

I highlighted those keywords in bold red, overriding the default coloring for keywords. I can extend the same idea to variable and field names:

Horizontal and vertical variable names

The implementation for emacs:

(tree-sitter-hl-add-patterns lang
  [
   ([(identifier) (property_identifier)]
    @variable.horizontal
    (.match? @variable.horizontal
             "(^q|^x\\d*|^x[A-Z]\\w*|^[cC]ols?|COLS|[wW]idth|WIDTH|[lL]eft|[rR]ight)$"))
   ([(identifier) (property_identifier)]
    @variable.vertical
    (.match? @variable.vertical
             "(^r|^y\\d*|^y[A-Z]\\w*|^[rR]ows?|ROWS|[hH]eight|HEIGHT|[tT]op|[bB]ottom)$"))
   ]))

and then you need to create faces tree-sitter-hl-face:variable.horizontal and tree-sitter-hl-face:variable.vertical.

Of course, these are just naming conventions, not encoded in the type system or checked in any formal way. But what if they were understood by the type system? Wouldn't it be handy to get a warning if you tried calling atan2(x, y) instead of atan2(y, x)? Or a warning for rect(x, x, w, h) instead of rect(x, y, w, h)? Maybe. I don't know!

I believe tree-sitter is able to flag something like atan2(x, y), but I didn't try implementing that.

What about other editors? Tree-sitter is in Atom, neovim, emacs, and vscode. And even without tree sitter, that regexp might be useful for highlighting any string with a word boundary pattern \b instead of ^ or $.

x and y variable names

Highlighting catches nowhere near as much as a type system, but it's so much easier to implement than a type system. I'll try it for a while and then decide whether to keep it. I like experimenting.

Labels: ,

2 comments:

Gus Hogg-Blake wrote at Thursday, July 7, 2022 at 7:38:00 AM PDT

Nice. I like simple programmer aids like this. Could you go even further and add some kind of visualisation element to it? I often get really confused trying to do things like account for scroll position when implementing drag and drop, not knowing what to add/subtract from what. Some kind of dev-tools like diagram of how the quantities in the expression you're building will affect the result in 2d (or even 1d, for a single axis) space could be helpful for that.

matklad wrote at Saturday, July 9, 2022 at 10:09:00 AM PDT

>Highlighting catches nowhere near as much as a type system, but it's so much easier to implement than a type system.

Note that in systems which has access to semantic info about code (old-school IDEs like IntelliJ, modern LSP servers) syntax highlighting is powered directly by the type checking results, and types of various things directly affect the colors.