# Get tab key to indent a block of code

Is there some way I can change Mathematica keyboard behavior so I could select a block of text/code, press tab, and the selection would be indented to right? Similarly, I would like shift+tab to produce indenting to the left.

If it were possible to get this behavior just for multi-line string text, or just in code cells, that would be great, too.

-
Normal mma cells don't have a clear notion of whitespace.. Tab works in code cells, but not for selected blocks, just as the first char of the line. If you're asking such questions, it's usually time to switch to WorkBench. Once I did my life became much easier:) For code cells this would still be very useful though (+1). –  Ajasja Jan 6 at 5:40
Hi @Ajasja. All my current important code is inside code cells or in packages. I tried workbench, but did not get used to it. I love the new autocomplete interface, collapse and expand code parts and the code execution in place for test, and it's not nice in Workbench. But maybe I have to try Workbench again. –  Murta Jan 6 at 10:34
Thanks for the accept. So, is my solution really usable for you? It is certainly not refined, and needs some more work to be robust and general. –  Leonid Shifrin Feb 22 at 16:19

The following solution seems to work reasonably well, at least on a few examples I have tested. It will be in the spirit of the one I gave to a rather similar earlier question you asked. I wasn't able to make the Tab key work, instead I bound the indenting to the CTRL+  combination - but in practice this is almost as easy as pressing Tab key. Also, the following is only a solution for indenting to the right. Indenting to the left is likely also possible, but might be a bit trickier to implement.

Here is the code. This is a generic function to construct a self-overwriting cell:

ClearAll[generateAutoOverwriteCell];
generateAutoOverwriteCell[
boxes : Except[_?OptionQ] : "",
type_String: "Input",
opts___?OptionQ
] :=
Module[{},
SelectionMove[EvaluationNotebook[], All, Cell, AutoScroll -> False];
SelectionMove[EvaluationNotebook[], Previous, Cell, AutoScroll -> False];
NotebookWrite[EvaluationNotebook[], Cell[BoxData[boxes], type, opts], All];
SelectionMove[EvaluationNotebook[], All, CellContents, AutoScroll -> False];
SelectionMove[EvaluationNotebook[], Previous, Character];
]


This is a relatively simple "formatter" for the selected part of your code:

ClearAll[process, $newlinePattern,$inner];

$newlinePattern = ("\n"|"\[IndentingNewLine]"); process[r_RowBox/;FreeQ[r,$newlinePattern]]:=RowBox[{"\t",r}];

process[x_]:=process[x,False];

process[RowBox[conts_List],flag_]:= RowBox[process[conts,flag]];

process[{left__,sep:$newlinePattern, right___}, flag_]:= { RowBox[{If[!TrueQ[$inner],"\t",Sequence@@{}],Sequence@@#}] & [
Block[{$inner = True},process[{left},False]] ] , sep , Sequence @@ Block[{$inner = False},process[{right}, True]]
};

process[{args__}/;FreeQ[{args},$newlinePattern],True]:={RowBox[{"\t",args}]}; process[x_,_]:=x/.block:{__,$newlinePattern, ___}:>process[block,False];


This is the key action rule, which I bound to the CTRL+  combination:

ClearAll[selectionTabRule]
selectionTabRule =
{"KeyDown", ""} :>
With[{nb = InputNotebook[]},
If[MemberQ[CurrentValue["ModifierKeys"], "Control"],
NotebookWrite[nb, process[sel]]
],
(* else *)
NotebookWrite[nb, ""]
]
];


Finally, here is the short-cut to construct such cells:

ClearAll[incell];
incell := generateAutoOverwriteCell[CellEventActions -> {selectionTabRule}];


Now, if you type incell into a new cell and evaluate, you will get a new cell with desired behavior. If you then copy and paste some code into this cell, you can start playing with it. Select the piece of code you'd like to move to the right, and press CTRL+ `. The code you select should be a complete expression or a sequence of expressions.

I am sure there are bugs and limitations in this simple solution. It is more in the spirit of showing how things might work, than being a complete solution here. I just find it interesting to explore the possibilities the FrontEnd can give us.

-