At the parser level, it's not all that difficult. The parser just needs a variable to keep track of the indentation level of the current block. And when it goes to read a new line, it counts leading spaces (or tabs) and compares the value against the indentation of the current block, then apply an algorithm that looks something like this:
if currentIndent = currentBlock.indent then
parse line in the context of currentBlock
else if currentIndent > currentBlock.indent then
create sub-block of currentBlock and parse line in that context
else finish currentBlock and run this same comparison on currentBlock.parent