11
$\begingroup$

I like to use terminals (e.g. gnome-terminal) where you can use the up key to copy the last command into the current input 'field'. For example, to repeat the last command you just have to press up, enter. Or, to modify the last input and re-run, it is just up, modify, enter.

As beginner I often make mistakes, or experiment by slightly changing previous inputs. Is there any way in which I can obtain this convenient input behavior in the Mathematica front end?

$\endgroup$
2
  • 6
    $\begingroup$ You can always just go back and edit that cell. Notebooks are not linear like a traditional command line. You can edit any previous input without needing to "recall" it. Perhaps you'll find this way of working more efficient if you get a bit used to it. $\endgroup$
    – Szabolcs
    Commented Mar 7, 2013 at 17:25
  • $\begingroup$ Have you seen edit to my answer? I am interested if it works with somebody else, because I didn't test it much. $\endgroup$
    – Vladimir
    Commented Apr 19, 2013 at 23:12

3 Answers 3

7
$\begingroup$

Have you tried shortcuts like cmd+L and cmd+Shift+L ? Perhaps these can be even overridden and generalized for next to last Input/Output cells and above. But, I'm still not sure how to do it.

Edit

Ok, so I managed to do it. (It took me almost two days, but I was inspired..)

To modify keyboard shortcuts or add new, it's necessary to change KeyEventTranslations.tr and/or MenuSetup.tr located in

$InstallationDirectory/SystemFiles/FrontEnd/TextResources/$OperatingSystem/

There are already several good ideas for making user defined keyboard shortcuts or menu items (1, 2, 3, 4, 5...), which can really save you some time at work once you adjust them as it suits. As these are system files, make sure to make a back-up before editing them. When/If you get more familiar with adding new shortcuts, you may also consider automating this procedure as shown here by Rolf Mertig.

For listing previous inputs in the selected notebook, in their original input form (what you asked), I made two new shortcuts and pasted them using text editor in KeyEventTranslations.tr right after the line EventTranslations[{

(*
Command Up   -   creates Terminal cell in which user can list previous inputs upwards to oldest
*)
Item[KeyEvent["Up", Modifiers -> {Command}], 
KernelExecute[With[{nb = SelectedNotebook[]},
 If[And[ValueQ[$TraceLine], NotebookFind[nb, "Terminal", Next, CellLabel] =!= $Failed],
  If[$TraceLine > 1,
	   $TraceLine = $TraceLine - 1;
	   SelectionMove[nb, All, CellContents];
	   NotebookWrite[nb,
	    ReplaceAll[ToBoxes[ReplaceAll[ReplaceAll[Hold[In[n] // InputForm], n -> $TraceLine], DownValues[In]]], RowBox[{"Hold", "[", Longest[Pattern[x,BlankSequence[]]], "]"}] -> x]
   ]
   , Beep[]
  ]
  , If[$Line > 1,
	   $TraceLine = $Line - 1;
	   SelectionMove[nb, After, CellGroup, 2];
	   NotebookWrite[nb, Cell[
	    BoxData[ReplaceAll[ToBoxes[ReplaceAll[ReplaceAll[Hold[In[n] // InputForm], n -> $TraceLine], DownValues[In]]], RowBox[{"Hold", "[", Longest[Pattern[x,BlankSequence[]]], "]"}] -> x]],
    "Input", CellLabel -> "Terminal", CellLabelAutoDelete -> False, ShowCursorTracker -> False
   ]];
   FrontEndExecute[FrontEndToken["MovePrevious"]]
   , Beep[]
  ]
 ]
]], MenuEvaluator -> Automatic
],
(*
Command Down   -   lists down previous inputs in Terminal cell down do most recent
*)
Item[KeyEvent["Down", Modifiers -> {Command}], 
KernelExecute[With[{nb = SelectedNotebook[]},
 If[And[ValueQ[$TraceLine], NotebookFind[nb, "Terminal", Next, CellLabel] =!= $Failed, $TraceLine < $Line - 1],
  $TraceLine = $TraceLine + 1;
  SelectionMove[nb, All, CellContents];
  NotebookWrite[nb,
   ReplaceAll[ToBoxes[ReplaceAll[ReplaceAll[Hold[In[n] // InputForm], n -> $TraceLine], DownValues[In]]], RowBox[{"Hold", "[", Longest[Pattern[x,BlankSequence[]]], "]"}] -> x]
  ]
  , Beep[]
 ]
]], MenuEvaluator -> Automatic
],

Abilities:

  • I've chosen ⌘↑ and ⌘↓, but one can as well set different in element KeyEvent[], where Modifiers can be "Shift", "Control", "Command", "Option"
    • For Macintosh: "Command" = Command Key, "Option" = Option Key
    • For Windows: "Command" = Alt, "Option" = Alt
  • When choosing key shortcut, be sure that there are no overlaps afterwards. For example, I have deleted original shortcuts for ⌘↑ and ⌘↓, from the file KeyEventTranslations.tr, before using them! But you can find some other or override original ⌘L

  • This routine uses global variable $Line and function In[]. Therefore functionality depends on setting $HistoryLength (through In[]). The routine also creates one global variable $TraceLine, which is unprotected as well as $Line

  • When pressing first time the shortcut key it creates a new cell close to current position of the cursor with a label "Terminal", where previous inputs are being listed (with a possibility for the change). After evaluation of the cell it will change its label to "In[$Line]:=" as all other input cells.
  • Before evaluating the cell "Terminal" user can go around and change, evaluate other cells and then continue listing inputs where he/she stopped, but only at the same "Terminal" cell - more than one will not be created, instead it will move your cursor automatically to that cell.

Any suggestions for improvements or simplifications are welcome.

$\endgroup$
2
  • $\begingroup$ Thanks. I've been looking for exactly this behavior. However, the code doesn't seem to be working on Windows. I gather that I don't need to find/replace "Command" with "Alt", correct? Using it as-is, should result in the key-bindings being set for alt+up and alt+down. I also didn't see any bindings with ["Up/Down", Modifiers->{Command}] in the file to delete. $\endgroup$
    – Brian H.
    Commented Sep 3, 2016 at 19:44
  • 1
    $\begingroup$ Hmm, seems the alt modifier is being globally used or overwritten to give focus to the menu bar. The script works when I changed the modifier to shift. $\endgroup$
    – Brian H.
    Commented Sep 3, 2016 at 19:45
3
$\begingroup$

Here is an approach using InString, EventHandler and DynamicModule.

  1. InString is used to retrieve the box structure for the input cells in the history.

  2. EventHandler is used to capture the keys , , enter, and esc.

  3. DynamicModule is used to create the dynamic interface.

Here's the code:

ViewInputs[Unevaluated[line_:$Line]] := With[
    {
    cellMargins = Replace[
        CurrentValue[{StyleDefinitions, "Input", CellMargins}],
        {{a_, _}, {_, _}} -> {{a, 0}, {0, 0}}
    ]
    },

    DynamicModule[{k = line},
        NotebookWrite[
            EvaluationCell[],
            Cell[
                BoxData @ TagBox[
                    DynamicBox[ToExpression@InString[k]],
                    EventHandlerTag[
                        {
                        "UpArrowKeyDown" :> (k=Mod[k-1, $Line-1, 1]),
                    "DownArrowKeyDown" :>(k=Mod[k+1, $Line-1, 1]),
                        {"MenuCommand", "HandleShiftReturn"} :> NotebookWrite[
                            EvaluationCell[],
                            ToExpression[InString[k]]
                        ],
                        "ReturnKeyDown" :> NotebookWrite[
                            EvaluationCell[],
                            ToExpression[InString[k]]
                        ],
                        "EscapeKeyDown" :> (
                            NotebookDelete[EvaluationCell[]];
                            SelectionMove[EvaluationNotebook[], Before, Cell]
                        ),
                        PassEventsDown->False
                        }
                    ],
                    Selectable->False
                ],
                "Input",
                Evaluatable->False,
                CellLabel->"↑: Up    ↓: Down    \[EnterKey]: Use    \[EscapeKey]: Cancel",
                CellLabelMargins -> cellMargins,
                CellLabelPositioning->Above,
                CellLabelStyle->Directive["CellLabel", FontSize->10],
                CellFrame -> {{False,False}, {False,True}},
                CellDingbat -> Cell[
                    BoxData @ TemplateBox[
                        {"\"In[\"", DynamicBox[ToBoxes@k], "\"]:=\""},
                        "RowDefault"
                    ],
                    "CellLabel",
                    FontFamily->"Helvetica",
                    FontWeight->"Plain",
                    ShowStringCharacters->False
                ]
            ]
        ];
        SelectionMove[EvaluationNotebook[], Before, CellContents];
    ];
]    

Using the up and down arrows cycles through the input history. Using enter or shift+enter replaces the interface with the input. Finally, using the escape key cancels the interface. Here's an animation showing the interface in action:

enter image description here

$\endgroup$
2
$\begingroup$

One easy thing to do is to get used to naming your cells. Start your cell with

 x1 = (cell contents)

then you can later go back and it already has a name. Alternatively, you can refer to cells by their number;

 In[27]

is the 27th cell defined in this session.

$\endgroup$
3
  • $\begingroup$ If I write 5! in cell 10, then In[10] evaluates to 120. Ideally, I need to be able to press something (e.g.<up>) during input mode in cell 11 that makes content of In[11] sames as In[10] (while still possible to edit it) $\endgroup$
    – ipy
    Commented Mar 7, 2013 at 17:13
  • 1
    $\begingroup$ There is also Control-L (Apple-L) that will copy down the input cell above your insertion point. $\endgroup$ Commented Mar 7, 2013 at 17:18
  • 1
    $\begingroup$ Thank so much for this! (any idea if something works for depth more than 1?) $\endgroup$
    – ipy
    Commented Mar 7, 2013 at 17:42

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.