6

I found that

setterm -regtabs 4

doesn't work in xterm or urxvt.

But, this

xterm_set_tabs () { 
  TERM=linux;
  export $TERM;
  setterm -regtabs 4
}

will circumvent the problem.

But, I suspect it is suboptimal as (1) I get a gfx bug I can't otherwise explain (at least, if I get the tab stuff right that possibility is ruled out), and (2) when I ssh to my school's Solaris, and run emacs -nw, it says the terminal "linux" is unknown! So then I have to change it back to "xterm". Of course, this is silly as all the while I'm using the same terminal.

Also, perhaps not relying on tabs at all is a good rule of thumb!

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Emanuel Berg
  • 6,903
  • 8
  • 44
  • 65

5 Answers5

8

The setterm utility is intended for use with the Linux console. According to the console_codes manual page:

The Linux console implements a large subset of the VT102 and ECMA-48/ISO 6429/ANSI X3.64 terminal controls, plus certain private- mode sequences for changing the color palette, character-set mapping, and so on.

Since the program is hard-coded,

/* -regtabs. */
if (ctl->opt_regtabs && vc_only(ctl, "--regtabs")) {
    int i;

    fputs("\033[3g\r", stdout);
    for (i = ctl->opt_rt_len + 1; i <= TABS_MAX; i += ctl->opt_rt_len)
        printf("\033[%dC\033H", ctl->opt_rt_len);
    putchar('\r');
}

it just happens to work with xterm since xterm implements VT100 controls (plus more).

As for large subset, that is debatable. In a quick count of the items in console_codes, I see 79 control sequences. That is far less than any of the xterm look-alikes documented in the xterm FAQ Comparing versions, by counting controls. By itself, 79 is not large. The VT102 itself (not an xterm look-alike) had 104. ISO-6429 (aka ECMA-48) documents 20 modes and 162 sequences. Whether you count the total as 182 or 162, 50% is not a large subset.

Rather than using a Linux console utility, there is a more portable choice: the tabs utility (in POSIX as well as Solaris). It is part of the ncurses utilities (and probably installed on your Linux system).

For the example given in the question, you could do this:

tabs -4

That uses the terminal database, rather than being hard-coded. Tabs and the control sequences to set them are documented in ECMA-48 and other places such as the terminfo(5) manual page.

And tabs works with xterm.

Thomas Dickey
  • 76,765
  • 2
    Where has that been all my life?! Some program I use is forever cocking up my tab stops, and I don't know (or care) which one it is. I just wanted my tab stops back. What's the procedure for hijacking a question so I can mark it answered? The embarrassing part is that a simple man -k tab|grep -i -v table |grep -i -v database would have uncovered it decades ago. – Erik Bennett Sep 08 '17 at 15:04
4

Many terminals support escape sequences that set tab stops. The capability has even an entry in terminfo(5): tbc (clear all tabs) and hts (horizontal tab set).

$ tput tbc; echo aaaaaaaaaaaaaaaaaaaaa$(tput hts); echo 'a\tb'
aaaaaaaaaaaaaaaaaaaaa
a                    b

Above we set a tab stop at the end of those aaaaaaaa, and we see the result on next line.

So, to set the tab stops, every 4 colums, we need:

tbc=$(tput tbc) hts=$(tput hts) cuf4=$(tput cuf 4)
printf '%s\r' "$tbc"
i=4
while [ "$i" -lt "$COLUMNS" ]; do
  printf %s "$cuf4$hts"
  i=$(($i + 4))
done
printf '\r'

Or you can also set tab stops at irregular intervals. Above we used "tput cuf" to move the cursor forward, while in the first example we used "aaaa". You can do:

printf '\r%s' "${tbc}aaaa${hts}aaaaa${hts}aaaaaaaa${hts}"

to set one tab stop at the 4th column, then the next one, 5 columns further...

  • Will this set the general tab width so that \t = " " if the tab width is 4? (Imagine four spaces, seems I can't write that.) – Emanuel Berg Aug 26 '12 at 21:03
  • OK, I see you've made an edit, answering my comment above. You seem to know a lot about this... Check out my answer below, is there a practical difference or are your solution simply much cooler? – Emanuel Berg Aug 29 '12 at 02:35
  • Hello again, just tried this and it breaks the cursor movement in emacs -nw just like my solution below. – Emanuel Berg Sep 01 '12 at 17:13
3

You can set the environment variable temporarily without needing to export it to your whole session using env:

env TERM=linux setterm -regtabs 4
Jim Paris
  • 14,337
2

In response to @Jim Paris:

Note that that only works for terminals that support the same escape sequences as linux virtual terminals to set tabs (and move the cursor forward).For instance, using "cat -v", we can see what sequence setterm is sending:

$ TERM=linux setterm -regtabs 4 | cat -vte
^[[3g^M^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^[[4C^[H^M

Luckily, it's the same sequences as supported by xterm:

~$ TERM=xterm tput tbc | cat -vte
^[[3g
~$ TERM=xterm tput hts | cat -vte
^[H
~$ TERM=xterm tput cuf 4 | cat -vte
^[[4C

And as it's the case of vt100, it's likely to be the case of most termnial emulators.

  • Better yet would probably be to set it native in xterm, urxvt, etc., not going sideways to the Linux virtual terminal. I suspect there is an .Xresources option for this; I'll keep looking. (Above, isn't it enough with cat -t?) – Emanuel Berg Aug 27 '12 at 09:19
-2

OK, I've read man xterm and there is no mention of tab width. I'm starting to think it is easiest just to reset TERM. In .bashrc:

function xterm_set_tabs () {
  TERM=linux
  export $TERM
  setterm -regtabs 4
  TERM=xterm
  export $TERM
}

if [ `echo $TERM` == "xterm" ]; then
  xterm_set_tabs
fi

Edit: This works for the problem described, but it has the side effect that when I run emacs -nw the cursor movement is messed up. As that is very serious, this is not an acceptable solution to the problem. (I'm unsure about site policy - should I remove my answer, or should I leave it so others will learn from the mistake as well? Obviously, I think it should remain. Anyhow, back to the drawing board.)

Emanuel Berg
  • 6,903
  • 8
  • 44
  • 65
  • TERM=linux setterm -regtabs 4

    is how you set the TERM variable to linux only for the setterm command. Are you sure you'll run that only in xterm terminals?

    – Stéphane Chazelas Aug 29 '12 at 06:00
  • So far the above has worked, the display in xterm is correct and I can ssh and then emacs -nw, but I'm absolutely not sure of any under the hood workings in this case. There are a lot of suggestions already, if you know their pros and cons, do tell, that's why we are here :) – Emanuel Berg Aug 29 '12 at 14:42