3

I'm on Ubuntu 12.04 and am using Terminator as my primary terminal. I like it because it lets me keep a python interpreter and bash terminal open at the same time, in the same view.

What is annoying is that I end up moving between directories A LOT, and then I have to do it twice. Is there a way to set up a terminator configuration to do that? To have terminator mirror directory changes.

I'm guessing I'm not the only one that finds that frustrating!

1 Answer 1

11

Ok. If I understand correctly, you basically have a Terminator window in a split view, where the one buffer is a Bash shell and the other is a Python interpreter. Now, whenever you type a command like cd Pictures/ in the Bash buffer, you want to automatically send the command os.chdir("Pictures/") to the Python buffer, so that it changes directories simultaneously with your Bash shell. Kind of like in this image:

enter image description here

...where the os.chdir command in the Python buffer should be entered automatically when you type a cd command in the Bash buffer. Right? If yes, here's a...

Solution

Step 1: Assign the two buffers to the same group

Terminator supports groups of windows. We'll assign those two buffers to the same group, in order to later use Terminator's feature of broadcasting commands to windows in the same group. In this example I will assign both buffers to a group named Tau (actual name doesn't matter, but make sure it's the same for both buffers).

enter image description here

Step 2: Define keyboard shortcuts to switch group broadcasting on and off

By default Terminator does not have keyboard shortcuts for these, but we need them now, so we'll define them via Terminator's Preferences menu. I used Ctrl+Insert to switch group broadcasting on, and Ctrl+Delete to switch it off. You can pick any other keyboard shortcuts you like, though you will have to adapt Step 3 appropriately.

enter image description here

Now, you can press Ctrl+Insert, and whatever you type in the one buffer will appear in the other buffer. By typing Ctrl+Delete you deactivate that behavior again.

If the Python interpreter understood a command such as cd Pictures/, to change a directory in both buffers, all you would have to do now would be something like Ctrl+Insertcd Pictures/Ctrl+Delete, to broadcast the command as is. But the normal Python interpreter does not understand this cd command. You could use IPython, which does understand it, instead of the pure Python interpreter. However I assume that (1) you want the pure Python interpreter and (2) you don't want having to remember pressing these key combinations before and after each cd command. So, let's head to Step 3.

Step 3: Translate and send the cd command automatically to the Python buffer

We will re-alias Bash's builtin cd command to do a little more before actually changing the working directory in the current shell. Namely, whenever a user types cd somewhere,

  1. We translate the command to Python
  2. We use xdotool to simulate pressing Ctrl+Insert
  3. We use xdotool to simulate typing the translated command
  4. We use xdotool to simulate pressing Return
  5. We use xdotool to simulate pressing Ctrl+Delete

In this way, the translated command will be sent to the Python buffer. If you don't have it, install xdotool:

sudo apt-get install xdotool 

The script that we want as an alias for cd will look something like this:

function cd_to_pybuf {
  xdotool type "#"
  xdotool key Ctrl+Insert
  xdotool type "os.chdir(\"$1\")"
  xdotool key Return
  xdotool key Ctrl+Delete
  cd "$1"
}
cd_to_pybuf

Explanation: When we alias cd to the above script, then whenever we type cd somewhere, Bash translates that to OURSCRIPT somewhere. Since our script ends with the function call cd_to_pybuf, it will actually call the function cd_to_pybuf with somewhere as argument (available as $1 within the function; note that bash expansion would not work here, so we can't use something like !* to get at the arguments of the original command, and $BASH_COMMAND is problematic too). This function performs exactly the steps enumerated above. On a sidenote, we also simulate typing # before we simulate pressing Ctrl+Insert, because whatever we type after that will appear in both buffers, and Bash does not understand the os.chdir command, so with that # sign we make it into a comment for Bash. After the xdotool stuff, we also perform the actual cd command in the Bash buffer.

So now, we re-alias cd to that script, and test it:

enter image description here

It works! That os.chdir("..") command in the Python buffer was typed automatically. I didn't do it. All I did was type cd .. in the Bash buffer. You can see that the command #os.chdir("..") was also automatically typed into the Bash buffer, but since it's a comment it had no real effect.

To make this change permanent, put that alias into ~/.bashrc, i.e., in your ~/.bashrc add the line:

alias cd='function cd_to_pybuf { xdotool type "#"; xdotool key Ctrl+Insert; xdotool type "os.chdir(\"$1\")"; xdotool key Return; xdotool key Ctrl+Delete; cd "$1"; }; cd_to_pybuf'

And voilà! That was it.

Bonus: an alias for pwd

Sometimes you may want to check what the current working directory is in both buffers at once. We can use the very same technique as for cd, and re-alias pwd. The following command will do the trick, and you can also put it into your ~/.bashrc if you like:

alias pwd='function pwd_to_pybuf { xdotool type "#"; xdotool key Ctrl+Insert; xdotool type "os.getcwd()"; xdotool key Return; xdotool key Ctrl+Delete; pwd; }; pwd_to_pybuf'

What you will have to remember

For this to work in the future, whenever you open up a split view with a Bash and a Python buffer, you will have to do two things:

  1. Assign both buffers to the same group in Terminator
  2. import os in your Python buffer

That's all.

Troubleshooting

This is not perfect. There are some minor problems:

  1. It's a little ugly that this #os.chdir thingy gets printed to the Bash buffer also. It's really cosmetic, but you might consider doing something different, e.g., after you simulated typing the command and before simulating pressing Return, deactivate broadcasting temporarily and remove that command (e.g., simulate a lot of backspaces, or the sequence Ctrl+A, Ctrl+K) from the Bash buffer or whatever.

  2. Some special arguments to cd will not work. Things like cd - (change to $OLDPWD), cd ~ (change to $HOME), or cd (without arguments, also change to $HOME). Here also, the script could be improved to account for such special cases (check if $1 is special, and translate appropriately). Such things should be a piece of cake from here, though.

  3. Optional parameters to cd, such as, e.g., cd -P somewhere, will not work because the translation would be os.chdir("-P") here. You could use $@ instead of $1 to look at all arguments, and then do the appropriate thing.

Hope I could help :) It was an interesting challenge!

3
  • 2
    HISTCONTROL=ignorespace is a common setting. So, if you prefix the # with a space, it's quite likely that it won't get saved in the history.
    – muru
    Aug 20, 2014 at 22:46
  • 1
    This is totally awesome! I use IPython, but it's nice to know that you can also hack terminator & bash into working with the standard Python interpreter! imgur.com/JQ2X0PF
    – Kasisnu
    Aug 21, 2014 at 13:43
  • You're welcome. Happy to see it helped :) Aug 21, 2014 at 14:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .