Reverse indentation

Python 2 - 137 131 bytes

i=raw_input().split('|')
f=lambda s:len(s)-len(s.lstrip())
d=sorted(set(map(f,i)))
for l in i:print' '*d[~d.index(f(l))]+l.lstrip()

Takes input with | instead of \n.

Explanation

The first three lines are fairly straightforward. Make a list of all the lines in the input, define a function that tells you how much leading whitespace a string has, and make a sorted list of values that function spits out for each line of input.

The last line is way more fun.

                                 l               # string with the line
                               f(l)              # amount of leading whitespace
                       d.index(f(l))             # where it is in list of whitespace amounts
                      ~d.index(f(l))             # bitwise NOT (~n == -(n+1))
                    d[~d.index(f(l))]            # index into the list (negative = from end)
           print' '*d[~d.index(f(l))]            # print that many spaces...
           print' '*d[~d.index(f(l))]+l.lstrip() # plus everything after leading whitespace
for l in i:print' '*d[~d.index(f(l))]+l.lstrip() # do the above for every line

CJam, 43 39 36 35 bytes

qN/_{_Sm0=#}%___&$_W%er]z{~S*@+>N}%

This looks toooo long. I am sure I am not Optimizing enough!

How it works:

Basic idea is to split the input on newline, calculate the number of leading spaces in each line, sort and get unique numbers, copy that array and reverse the copy, transliterate the original in-order numbers with this two arrays and then finally form the final string using this information.

The lengthiest part is to figure out how many leading spaces are there in each line as CJam does not have an easy way of doing it.

Code expansion:

qN/_                                      "Split the string on newline and take copy";
    {_Sm0=#}%                             "Map this code block on the copy";
     _Sm                                  "Copy the string and remove spaces from the copy";
        0=                                "Get first non space character";
          #                               "Gets its index in original string";
             ___                          "Get 3 copies of the above array";
                &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
                                          "the unique reverse sorted in the copy";
                       ]z                 "Get array of [row,
                                          " original number of leading spaces,
                                          " required number of leading spaces]";
                         {~S*@+>N}%       "For each above combination";
                          ~S*             " unwrap and get leading space string";
                             @+           " prepend to the row";
                               >          " remove original spaces";
                                N         " put newline";

And in the spirit of the question. A real expansion of the code:

                                          qN/_                                      "Split the string on newline and take copy";
                                {_Sm0=#}%                             "Map this code block on the copy";
                               _Sm                                  "Copy the string and remove spaces from the copy";
                             0=                                "Get first non space character";
                          #                               "Gets its index in original string";
                         ___                          "Get 3 copies of the above array";
                       &$_W%                     "Get unique elements, sort, copy and reverse";
                     er                   "Transliterate unique sorted elements with";
"the unique reverse sorted in the copy";
                ]z                 "Get array of [row,
" original number of leading spaces,
" required number of leading spaces]";
             {~S*@+>N}%       "For each above combination";
          ~S*             " unwrap and get leading space string";
        @+           " prepend to the row";
     >          " remove original spaces";
    N         " put newline";

7 bytes saved thanks to Martin and 1 byte thanks to Dennis

Try it online here


JavaScript, ES6, 113 103 101 bytes

I am pretty sure this can be golfed at least a little further, but here goes.

Never would have thought that there will be a 101 bytes JS solution, beating Python!

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))

This creates a method named f which can be called with the input string. If you are in a latest Firefox, you have template strings and you can call the method like

f(`a
  b
  c
d
   e
        f
  g
   h`)

Otherwise, you can also call it like

f("a\n\
  b\n\
  c\n\
d\n\
   e\n\
        f\n\
  g\n\
   h")

or, try the snippet below:

g=_=>O.textContent=f(D.value)

f=a=>(b=c=[...Set(a.match(r=/^ */gm).sort())],c.map((x,i)=>b[x]=c.slice(~i)[0]),a.replace(r,x=>b[x]))
<textarea id=D></textarea><button id=B onclick=g()>Inverse!</button>
<pre id=O></pre>