0

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.

1
  • The indenting problem in the Update was an issue in graphql-mode and I've since submitted a pull request github.com/davazp/graphql-mode/pull/50. The issue has been merged and I think this question isn't going to get any "more emacs idiomatic" answers. I'll mark it as answered by myself if no one has any better suggestions.
    – flooose
    Jul 17, 2022 at 15:30

1 Answer 1

0

As described in the comment, I think polymode is the way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.