Hacker News new | past | comments | ask | show | jobs | submit login
Polymode: Multiple Major Modes and How to Use SQL and Python in One Buffer (masteringemacs.org)
40 points by perihelions on Feb 4, 2023 | hide | past | favorite | 8 comments



It's kind of hard to fully appreciate how powerful polymode is without actually _using_ it. When you use an editor that can mostly-understand the syntax behind markup like fenced markdown code blocks like this:

```ruby

puts "Hi"

```

You may be used to native syntax highlighting take over, but while you're in polymode, moving the cursor into the Ruby portion of the code actually activates Ruby-mode - any code checking (with something like flymake) works as expected, any major-mode specific actions that reformat code like M-q or == (while evil is active) will do what you expect, and polymode isn't just limited to fenced markdown.

Like the linked article demonstrates, polymode is super flexible. I myself wrote my own, small polymode that watches for comments like /* python */ that precede literal string blocks (which look like ''print("Hi")'' and are usually multi-line) in nix code to transform regions into their native modes (it doesn't need to just be python) and it's really great.

You can see an animated description of this here: https://twitter.com/leothrix/status/1597327756102336512

edit: my fenced block example was weird


Of course, now that tree-sitter is embedded in the upcoming Emacs 29, expect even better support than polymode to emerge over time as you can dole out parcels of your buffer to different language parsers.


How does the language detection work?


When adding languages you define a function/regex to match the start and end positions of each language block. Polymode then scans the document, and runs the matchers.

e.g this matches markdown code blocks (and also extracts the language from the start to select the mode to run)

    (define-auto-innermode poly-markdown-fenced-code-innermode
      :head-matcher (cons "^[ \t]*\\(```{?[[:alpha:]].*\n\\)" 1)
      :tail-matcher (cons "^[ \t]*\\(```\\)[ \t]*$" 1)
      :mode-matcher (cons "```[ \t]*{?\\(?:lang *= *\\)?\\([^ \t\n;=,}]+\\)" 1)
      :head-mode 'host
      :tail-mode 'host)
( via https://polymode.github.io/defining-polymodes/ )


If this has good enough performance it could be a big deal for org-babel. We've struggle to implement good/sane editing of blocks in the same buffer, and popping out to another buffer is a hacked workaround most of the time.

Will definitely give this a spin.


I came up with a neat trick to use Python type annotations to tag multi line string as different languages, and a VSCode plugin for it: https://github.com/samwillis/python-inline-source

The difficulty is that it would need a completely new langue server to support auto-completion. Currently it only does syntax highlighting.


My head is already coming up with use-cases, such as JS template literals (think lit [0] for HTML and CSS templates) or the recently-shared Expr [1]. This is really neat. Thanks for sharing.

[0] https://lit.dev/

[1] https://github.com/antonmedv/expr


Does something like this exist for Neovim?




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: