rluisr
rluisr

Reputation: 351

Sort a HCL block with specific property's value

I would like to sort an HCL block with env

Before

resource "datadog_monitor" "A" {
  tags = ["env:stg"]
}

resource "datadog_monitor" "B" {
  tags = ["env:dev"]
}

After

resource "datadog_monitor" "B" {
  tags = ["env:dev"]
}

resource "datadog_monitor" "A" {
  tags = ["env:stg"]
}

Upvotes: 0

Views: 97

Answers (2)

romainl
romainl

Reputation: 196751

The usual way is to squeeze the blocks into single lines, sort those lines, and then expand the blocks back to their original form. Assumption: the buffer only contains those blocks.

  1. Squeeze

    :[range]g/^res/.,/^}/s/\n/§
    

    Explanation:

    • on each line starting with res in [range] (% by default),
    • substitute the EOL \n with a fancy character §.

    Result:

    resource "datadog_monitor" "A" {§  tags = ["env:stg"]§}§
    resource "datadog_monitor" "B" {§  tags = ["env:dev"]§}§
    
  2. Sort

    :[range]sort /env/
    

    Explanation:

    • sort lines in [range] (% by default),
    • based on what comes after env.

    Result:

    resource "datadog_monitor" "B" {§  tags = ["env:dev"]§}§
    resource "datadog_monitor" "A" {§  tags = ["env:stg"]§}§
    
  3. Unsqueeze

    :[range]g/^res/s/§/\r/g
    

    Explanation:

    • on each line starting with res in [range] (% by default),
    • substitute every fancy character § with the appropriate EOL character.

    Result:

    resource "datadog_monitor" "B" {
      tags = ["env:dev"]
    }
    
    resource "datadog_monitor" "A" {
      tags = ["env:stg"]
    }
    

See :help :range, :help :global, :help :substitute, :help :sort.

Upvotes: 1

B.G.
B.G.

Reputation: 6026

Well this is not trivial. Vim sort has a regex for sorting patterns.

:'<,'>sort /tags = \["env:/

Does tell vim to ignore everyting up to "env: and just sort afterwards. But this applies to lines of codes not blocks. so your code will be split up.

To work around this in vim, one could join the relevant lines together before sorting:

:g/tags/norm JkJ

This allows the sort before to work. Splitting it again then is trivial:

:%s/{/{\r/g
:%s/}/}\r/g

But in the end, I guess there must be better tools than vim for that. Maybe someone knowing awk really well could create an more elegant solution. (And there are possibly also other vim solutions).

Upvotes: 0

Related Questions