I'm looking for a way to make the indentation in HEREDOCs better. In my case, it's specifically in Ruby, but maybe this is a general question. Basically, I have the following situation: in our tests, we write a lot of graphql queries in HEREDOC form. We use line breaks and indentation in these queries, so that they are more readable. I'd like something similar to what was described here
https://stackoverflow.com/questions/9741931/primitive-indentation-in-emacs
and implemented in a corresponding gist here
https://gist.github.com/mishoo/5487564
but I'm wondering if there is a more emacs idiomatic way?
I tried going at it with polymode:
(require 'polymode) (define-hostmode poly-ruby-hostmode :mode 'ruby-mode) (define-innermode poly-ruby-gql-metadata-innermode :mode 'graphql-mode :head-matcher "[[:space:]]*<<[~-]GRAPHQL" :tail-matcher "[[:space:]]*GRAPHQL" :head-mode 'host :tail-mode 'host) (define-polymode poly-ruby-mode :hostmode 'poly-ruby-hostmode :innermodes '(poly-ruby-gql-metadata-innermode)) But although this "works" for the following:
def bla <<~GRAPHQL query ($parent: ParentDamageParticipantInput) { damageObjects(parent: $parent) { items { id } } } GRAPHQL end it bonks the indentation. When I say "works", I mean, when I'm in the GRAPHQL code block, the modeline correctly shows GraphQL as the major mode and when I'm outside of it, it shows Ruby as the major mode. Maybe there's something else wrong with my polymode definition.
Update
I've figured out why my polymode isn't working correctly (mostly). It has to do with the :header-matcher and :tail-matcher. There has to be a new line at the end of each matcher, i.e.
(define-innermode poly-ruby-gql-metadata-innermode :mode 'graphql-mode :head-matcher "[[:space:]]*<<[~-]GRAPHQL\n" :tail-matcher "[[:space:]]*GRAPHQL\n" :head-mode 'host :tail-mode 'host) Furthermore, I've taken away the [[:space:]]* from each one and simply done a .*, so the final definition looks as follows.
(require 'polymode) (define-hostmode poly-ruby-hostmode :mode 'ruby-mode) (define-innermode poly-ruby-gql-metadata-innermode :mode 'graphql-mode :head-matcher ".*<<[~-]GRAPHQL\n" :tail-matcher ".*GRAPHQL\n" :head-mode 'host :tail-mode 'host) (define-polymode poly-ruby-mode :hostmode 'poly-ruby-hostmode :innermodes '(poly-ruby-gql-metadata-innermode)) This is better, but the result is an indentation that looks as follows:
def bla blubb = <<~GRAPHQL query bla($parent: Int) { foo bar { id babar { id type } } } GRAPHQL end Ideally, I'd like the foo in the HEREDOC indented two spaces already and everything in curly braces after that to be indented an additional two spaces. That would make it indent the way that graphql-mode indents when it's not used in the context of polymode.
P.S. in the last code block, the graphql code looks all green, even though the indentation now works. This is a side-effect of the syntax highlighting of StackExchange. In reality, my emacs also had proper syntax highlighting for the graphql text.