# $COLUMNS and $LINES empty in %sh{}

**URL:** <https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345>\
**Category:** Help\
**Created:** [November 23, 2023, 5:21pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345 "2023-11-23T17:21:24Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 23, 2023, 5:21pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/1 "2023-11-23T17:21:24Z")

</div>

Environment:  
Debian 12, Kitty 0.31.0 using bash, Kakoune 2022.10.31  
echo $COLUMNS works at the bash prompt  
kak (to open an empty session)  
:echo %sh{ echo $COLUMNS $LINES } (returns nothing)  
there is a work around in that  
kitty @ ls|jq ‘..tabs.windows|select(.is\_self == true).columns’  
will give columns when run in %sh{}

It looks to me like the kakoune shell environment is not setting $COLUMNS and $LINES  
would appreciate any suggestions on how to diagnose further  
should I open a bug report?

thanks,  
Greg  
edited to change %LINES to $LINES

---

<div class="post-metadata">

**Author:** ![ftonneau](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/ftonneau/32/295_2.png) [@ftonneau](https://discuss.kakoune.com/u/ftonneau)\
**Post date:** [November 23, 2023, 6:41pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/2 "2023-11-23T18:41:53Z")

</div>

This is more likely to be a shell problem than a Kakoune problem. COLUMNS and LINES are not environment variables that your shell (e.g., Bash) detects and sets correctly whenever it runs. From its man page, Bash seems to detect COLUMNS and LINES only if the `checkwinsize` option is on and/or when Bash runs interactively.

A more reliable way to detect COLUMNS and LINES from your shell may be to call the `stty` command. Thus, typing:

> evaluate-commands %sh{info=$(stty size \</dev/tty); echo “echo $info”}

or, more simply:

> echo %sh{stty size \</dev/tty}

on Kakoune’s command line does give the correct response on my machine, whereas your code only gives an empty response.

NB: here, the `</dev/tty` input redirection makes sure that the input to `stty` is from the actual, controlling terminal.

---

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 23, 2023, 8:01pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/3 "2023-11-23T20:01:41Z")

</div>

Thanks François, that works for me. Thanks for pointing to checkwinsize. I compared set output from the kitty terminal and from %sh{}. checkwinsize is set in BASHOPTS on my terminal, but not in %sh{}. In fact there are no settings starting with BASH at all under %sh{}.

Kakoune has to deal with a lot of different shells so I suspect Kakoune is only supporting a subset of all shells functionality and for some reason $COLUMNS falls outside that subset. I appreciate how responsive this relentless focus on orthogonality makes Kakoune so am fine with using either kitty @ ls or stty size instead of $COLUMNS

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [November 24, 2023, 12:41am UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/4 "2023-11-24T00:41:24Z")

</div>

`%sh{}` should not have `$COLUMNS` or `$LINES` set, because the shell commands in that block do not have any lines or columns - they are not connected to a terminal, so they can only output a simple byte stream.

You might say “Ah, but Kakoune runs in a terminal, so it should have access to those things!” The Kakoune _client_ runs in a terminal, but `%sh{}` blocks are run by the Kakoune _server_ which may not have access to a terminal - for example, if the server was started with `kak -d`, or if it was running in a terminal that got closed.

However, most people (I think) just run `kak` and never run `:new` or `kak -c` to connect any other clients, in which case interacting with `/dev/tty` should work.

---

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 24, 2023, 4:43am UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/5 "2023-11-24T04:43:02Z")

</div>

Thanks to both François and Screwtapello for your comments. I appreciate your help in deepening my understanding of Kakoune architecture.

Yes, this is occurring under kak i.e. client+server all-in-one, as best I can tell there is only 1 kak pid.

“set” output for %sh{} includes some KITTY environment variables like KITTY\_WINDOW\_ID - I suppose that is a KITTY id, not a shell characteristic. It looks to me like Kakoune is actively choosing a subset of the environment variables of the shell it starts in and presumably actively filtering out environment variables with name starting with BASH, $LINES, $COLUMNS and perhaps others.

As you point out the Kakoune client appears to be using the same number of columns and lines as the underlying terminal so the Kakoune client must be aware of these dimensions.

Inside %sh{} I’m running a report on a buffer in kak and directing the output to -fifo buffers in the same kak. The report needs know how wide the terminal is to properly format. I have been running this as a standalone bash script which meant it had access to $COLUMNS. I viewed it in less. It produced error messages to the terminal. I find it convenient to have the original data, the report and error messages all in Kakoune buffers for consistent viewing/editing in one Kitty window.

I connected with kak -c and %sh{} reports the terminal size of the original window which is different than the size of the window running kak -c. The KITTY\_WINDOW\_ID was also for the original window. BTW this seems like an easy way to view Kakoune buffers side by side if needed. I’ve started with 1 buffer/kak but can now see stacking up more buffers/kak. It’s nice to keep stumbling over powerful new features of Kakoune.

I closed the original kak and now the stty size is null as you indicate. KITTY\_WINDOW\_ID still points to the window where the original kak used to be running so it’s now invalid. kitty @ ls|jq ‘..tabs.windows|select(.is\_self == true).id’ incorrectly points to the original window as well. It looks like the kak server forked to the background is holding on to the kitty window it was running in because I can’t exit that bash session until I close the client. For now, I want to avoid this situation instead of trying to figure it out, but it’s good to know what can happen.

Thanks for the in-depth response.  
Greg

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [November 24, 2023, 8:05am UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/6 "2023-11-24T08:05:53Z")

</div>

> [@gregk](#):
>
> It looks to me like Kakoune is actively choosing a subset of the environment variables of the shell it starts in and presumably actively filtering out environment variables with name starting with BASH, $LINES, $COLUMNS and perhaps others.

When `bash` starts up, any environment variables it inherits are available with a `$` prefix, like `$PATH` or `$HOME`. There are a bunch of other values that you can access with a `$` prefix, like `$BASH_VERSION` or `$COLUMNS`, and `set` lists them all side-by-side, so it’s easy to assume they’re all the same kind of thing, but they’re not. There are “shell variables” and “environment variables”, and they’re different.

- At startup, the shell inherits a load of environment variables, and imports them as shell variables.
- any additional variables defined by shell commands are “shell variables”
- the `export` command converts a shell variable into an environment variable
- when the shell launches an external command, the external command receives environment variables in its environment, but does not receive shell variables at all, even if it’s another shell
- The `set` builtin, when run without any arguments, lists all the shell variables defined in the current shell.
- `/usr/bin/env` is an external command which, when run without any arguments, lists all the environment variables it has inherited

In a fresh terminal running `bash`:

```console
$ set | wc -l
2242
$ env | wc -l
75
$ set | grep COLUMNS; echo done
COLUMNS=119
done
$ env | grep COLUMNS; echo done
done

```

> [@gregk](#):
>
> Inside %sh{} I’m running a report on a buffer in kak and directing the output to -fifo buffers in the same kak. The report needs know how wide the terminal is to properly format.

If you want to know how wide the Kakoune buffer is, so a report can be properly formatted inside it, you might want to use the `%val{window_width}` expansion. It’s not _completely_ reliable, as it doesn’t subtract the width of line-flags highlighters (like line-numbers), but it’s more reliable than trying to poke at `/dev/tty` from the Kakoune server.

> [@gregk](#):
>
> It looks like the kak server forked to the background is holding on to the kitty window it was running in because I can’t exit that bash session until I close the client.

Kitty exports its information as environment variables so they’re inherited by every descendent process, unless those variables are explicitly cleared the way that (for example) `sudo` or `env -i` do.

---

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 24, 2023, 1:17pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/7 "2023-11-24T13:17:15Z")

</div>

This is a great deep dive into %sh{}. I like the one liners like env|grep COLUMNS that illuminate what’s going on.

kitty @ ls is keying on $KITTY\_WINDOW\_ID in %sh{} to know what the current window is. That explains why it’s unreliable when there are separate kakoune clients and servers.

changes to KITTY\_WINDOW\_ID are only valid for the current invocation of %sh{}. It looks like %sh{} resets it’s environment variables from the original shell with each invocation.

$kak\_window\_width works and also gives the correct width for a client window even when it’s different from the original window. $kak\_window\_width looks like a complete solution to the original question.

The following is way above and beyond the original question. I’d be glad to start a new topic if that’s the custom on this forum.

%sh{} picks up the correct window\_width per server, client and invocation. how about %sh{} also picking up the environment variables in the clients shell instead of the server shell when creating %sh{} for a client? so that it picks up the correct KITTY\_WINDOW\_ID for the client? If kakoune were to key off the client environment then perhaps the server could just transfer to the next client when the original kak session is closed. Or at least Kakoune wouldn’t need to hang on to the original terminal session when the kakoune running there is closed…

If I open kak in gnome-terminal, then -c connect to it from a Kitty window, the kitty client %sh{} has no $KITTY\_WINDOW\_ID at all.

thanks,  
Greg

---

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 25, 2023, 4:24am UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/8 "2023-11-25T04:24:08Z")

</div>

%val{client\_pid} gives the correct client pid  
kitty @ ls includes pids  
Here is a rather crude jq to determine the correct kitty tab and windowid by matching on pid  
echo %sh{  
kitty @ ls |jq -c ‘..tabs|select(.windows.foreground\_processes.pid ==’$kak\_client\_pid’)|{“tid”:.id}, (.windows|select(.foreground\_processes.pid ==‘$kak\_client\_pid’)|{“wid”:.id})’  
}  
sample output  
{“tid”:4}  
{“wid”:11}  
This provides reliable access to the extensive information in kitty @ ls including .columns which should be correct in all the scenarios raised so far in this topic including separate client and server pids.

It may even be possible to get kitty @ ls --match and --match-tab to work correctly in %sh{} by setting KITTY\_WINDOW\_ID correctly

How cool that set -x works in %sh{}!

I would still like to understand why Kakoune uses the server env variables in client sessions, but thanks to your help I’m set to bump up my kakoune integration with kitty a couple of notches.

---

<div class="post-metadata">

**Author:** ![gregk](https://discuss.kakoune.com/letter_avatar_proxy/v4/letter/g/958977/32.png) [@gregk](https://discuss.kakoune.com/u/gregk)\
**Post date:** [November 25, 2023, 8:52pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/9 "2023-11-25T20:52:11Z")

</div>

Just as it would seem reasonable for a kakoune client to inherit it’s environment variables from the shell where kak -c launched it, wouldn’t it be logical for .dev/tty in the client %sh{} to point to the shell where kak -c launched it? I can imagine there are tradeoffs in designing a server-client system and so far everything I’ve encountered about Kakoune is well thought-out so perhaps there are reasons to point to the server shell.

There is plenty of kakoune function I can start to take advantage of. I’m just curious if there is anything more I might be able to do by better understanding the client-server design.

---

<div class="post-metadata">

**Author:** ![krobelus](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/krobelus/32/616_2.png) [@krobelus](https://discuss.kakoune.com/u/krobelus)\
**Post date:** [November 25, 2023, 11:25pm UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/10 "2023-11-25T23:25:39Z")

</div>

> Just as it would seem reasonable for a kakoune client to inherit it’s environment variables from the shell where kak -c launched it,

Hmm I’m not sure. I’ve gotten used to the current behavior and it seems the simplest choice overall. The idea of using the client env is interesting. I reckon that when we explore it further, we’ll discover why it’s not a good idea.  
In my experience the client env vars are only necessary for UI related decisions.  
For that we can access them explicitly using `%val{client_env_FOO}`.  
For example `tmux.kak` uses `tmux -t ${kak_client_env_TMUX_PANE}`

> wouldn’t it be logical for .dev/tty in the client %sh{} to point to the shell where kak -c launched it

yeah I don’t think the current /dev/tty is useful. There are a couple approaches to change this but I’m wary of added complexity.  
Today we can access the client’s TTY with `/proc/$kak_client_pid/fd/0` (not POSIX).

---

<div class="post-metadata">

**Author:** ![Screwtapello](https://discuss.kakoune.com/user_avatar/discuss.kakoune.com/screwtapello/32/12_2.png) [@Screwtapello](https://discuss.kakoune.com/u/Screwtapello)\
**Post date:** [November 26, 2023, 4:40am UTC](https://discuss.kakoune.com/t/columns-and-lines-empty-in-sh/2345/11 "2023-11-26T04:40:11Z")

</div>

> [@gregk](#):
>
> This is a great deep dive into %sh{}. I like the one liners like env|grep COLUMNS that illuminate what’s going on.

Thank you! I’m glad you found it helpful!

> [@gregk](#):
>
> It looks like %sh{} resets it’s environment variables from the original shell with each invocation.

When Kakoune encounters a `%sh{)` block, it launches a new shell process to execute it, which naturally inherits its environment variables from the Kakoune server. The shell process can set its own variables and export them to any child processes it launches, but it can’t do anything to affect the environment in the parent Kakoune process.

> [@gregk](#):
>
> I would still like to understand why Kakoune uses the server env variables in client sessions, but thanks to your help I’m set to bump up my kakoune integration with kitty a couple of notches.

There’s not really any such thing as a client session; a Kakoune client just lets you interact with the server much like how a web browser lets you interact with a web server. As krobelus points out, though, if you mention the expansion `client_env_FOO` (`%val{client_env_FOO}` in Kakoune, or `$kak_client_env_FOO` in a shell block) then the server will try to figure out which client is involved, and ask it for the contents of its environment variables.

> [@gregk](#):
>
> Just as it would seem reasonable for a kakoune client to inherit it’s environment variables from the shell where kak -c launched it, wouldn’t it be logical for .dev/tty in the client %sh{} to point to the shell where kak -c launched it?

Again, there’s no “client `%sh{}`”. If you open up a Kakoune client and type `:echo %sh{date}<ret>` then those individual keys are sent from the client to the server, and then the server interprets them as a command and executes them. The client never executes anything, and does not know what is a command and what isn’t.

I expect the reason for this centralisation is that Kakoune scripts can affect the entire state of the server, including every buffer (`eval -buffer FOO some-command`) and client (`eval -client FOO some-command`) and it’s a lot easier to implement that if all the information is stored in one process, rather than multiple processes having to communicate and collaborate to make that happen.
