Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand the new/terminal API #4425

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

Expand the new/terminal API #4425

wants to merge 8 commits into from

Conversation

lenormf
Copy link
Contributor

@lenormf lenormf commented Nov 5, 2021

This PR allows users to control more accurately where new Kakoune clients are spawned via the :new API: vertical horizontal, window.

The terminal API had to be extended similarly as a consequence. I also noticed that a terminal-tab alias was sneaked into kitty.kak, so that’s supported as well, since tabs are a common type of window nowadays. Not all our multiplexer support scripts implement it though.

The other commits are consistency fixes or cosmetics.

Fixes #3943.

@mawww
Copy link
Owner

mawww commented Nov 7, 2021

I am not sure this is the right approach, and I think the new command illustrates my issue with it very nicely: This is a viral change that requires every command that relies on terminal to be duplicated for each possible way to open a new terminal.

I think there is a real problem to solve here, there is a class of scripts that do need extra control on how things are split, a diffing script for example wants to be able to do vertical splitting to ensure it does get each pane side by side. Those scripts are relatively rare though, and I dont have a solution for them yet.

@lenormf
Copy link
Contributor Author

lenormf commented Nov 7, 2021

I agree, I don’t like this approach either. You could almost make the argument that the editor doesn’t need to be that aware of multiplexing environments in the first place.

I don’t have any ideas, so in the meantime here’s a patch users can compile in to fill the gap.

By the way, a good example of a script that could use deterministic client placement from within Kakoune is my Git merge tool, kakmerge!

@lenormf
Copy link
Contributor Author

lenormf commented Nov 7, 2021

Also note that this PR has a bunch of commits that could be considered for merging, independently of the new/terminal API modifications.

@alexherbo2
Copy link
Contributor

alexherbo2 commented Nov 7, 2021

Just random ideas and issues I encountered while using Kakoune and its windowing system.

I also think the problem is more profound and I don’t have a solution too.

Window mode

Helix has a window mode on Control+W.

Explicit windowing

There is valid reasons to open a TUI program in Alacritty when in tmux.

If we have fzf using the terminal command, there is no way to open in Alacritty.

Client scope

Example: Start Kakoune in Alacritty then open a client in tmux.

The windowing detection is done on startup, instead on the client creation, and aliases are global.

Window role

Example: fzf popup and sidetree panel.

See WindowType for naming convention.

Passing variables

Example how to pass environment variables to a program in the shell:

%sh{
  variable=value program
}

Currently, we emulate variable passing with a Kakoune command taking another Kakoune command with a certain pattern.

define-command -override connect -params 1.. -command-completion -docstring 'Run a command as <command> sh -c {connect} -- [arguments].  Example: connect terminal sh' %{
  %arg{1} sh -c %{
    export KAKOUNE_SESSION=$1
    export KAKOUNE_CLIENT=$2
    shift 3

    [ $# = 0 ] && set "$SHELL"

    "$@"
  } -- %val{session} %val{client} %arg{@}
}

define-command -override run -params 1.. -shell-completion -docstring 'Run a program in a new session' %{
  nop %sh{
    nohup "$@" < /dev/null > /dev/null 2>&1 &
  }
}

I was hoping for a more convenient way.

Occasion for better naming?

new and terminal could have better names, especially terminal-tab and their variants.

@alexherbo2
Copy link
Contributor

Could 4433 solve the issue of windowing?

What if instead of writing Kakoune commands, we could add shell commands to path?

That way a fzf integration for Kakoune would be just:

terminal :fzf

Note: :fzf is a shell command, where : is a naming convention.

It was an approach explored in connect.kak.

It means the new variants could be just:

run tmux split-window :attach

Or more conveniently if using an alias:

split-window :attach

@lobre
Copy link
Contributor

lobre commented Oct 5, 2023

Is this PR still "valid" in terms of design as of today?

@mawww
Copy link
Owner

mawww commented Oct 9, 2023

I still have the same concerns, while having more control over where/how the terminal is created would be great, I do not think this should be done through introducing new commands.

Some approach that comes to mind would be to allow alias to refer to other aliases, which would allow:

alias current terminal terminal-vertical
new
<restore the previous alias ?>

Then we could possibly have a way to temporarily set an alias for a command (I have been wondering about such a feature for a while, not only for aliases but for various other values such as options as well)

with-alias terminal terminal-vertical new

This is still unsatisfying as we need to maintain the terminal, terminal-vertical and terminal-horizontal aliases and can get in weird configuration (terminal being manually set to use iterm while terminal-vertical is still to the previous auto detected tmux-terminal-vertical value ?)

So yeah, I think this needs more design work.

@lobre
Copy link
Contributor

lobre commented Oct 10, 2023

while having more control over where/how the terminal is created would be great, I do not think this should be done through introducing new commands.

Just to kick open doors, I have recently spent time discovering and using the Plan 9 Acme editor. And it made me realize how important the proximity between the editor and the windows can be. Opening windows is not an arbitrary action in Acme. Effectively: "The initial placement of a new window is determined automatically".

To have more details, here is an extract of the initial paper:

Acme tiles its windows and places them automatically to avoid asking the user to place and arrange them. For this policy to succeed, the automatic placement must behave well enough that the user is usually content with the location of a new window. The system will never get it right all the time, but in practice most windows are used at least for a while where Acme first places them. There have been several complete rewrites of the heuristics for placing a new window, and with each rewrite the system became noticeably more comfortable. The rules are as follows, although they are still subject to improvement. The window appears in the ‘active’ column, that most recently used for typing or selecting. Executing and searching do not affect the choice of active column, so windows of commands and such do not draw new windows towards them, but rather let them form near the targets of their actions. Output (error) windows always appear towards the right, away from edited text, which is typically kept towards the left. Within the column, several competing desires are balanced to decide where and how large the window should be: large blank spaces should be consumed; existing text should remain visible; existing large windows should be divided before small ones; and the window should appear near the one containing the action that caused its creation.

I know Acme and Kakoune are really different, as Acme can almost be seen as a window manager while Kakoune wants to delegate this part. But my point is that I think the editor should be able to control the position, size and content of windows. Simply throwing at the window the command: "create a new window" might not be enough to implement a comfortable multi-file experience.

After a few weeks of using Acme, I am amazed at how the editor opens things at the correct location. It is rare that I have to reposition windows by myself.

A few simple examples that could be enjoyable in Kakoune if it could better control windows:

  • open the *grep* window at the bottom taking one-fourth of the viewport's height.
  • when searching for a keyword definition, open the definition in a column at the right.
  • more generally when searching for code or browsing code, keep windows with edited buffers on the left column, and open "reference buffers" on the right column.
  • see the man page of the command at the cursor in a new window at the top of the current one.

I know those examples might be against the Kakoune philosophy, but I just try to defend the other side of the spectrum to demonstrate what it can bring in terms of developer experience.

Not all window systems have this possibility, but that would be nice to be able to control at least the position (right/left/up/down) and default for instance to right for new or when the implementation does not allow to choose the position. And maybe the relative size of the newly created window.

@mawww
Copy link
Owner

mawww commented Oct 11, 2023

  • open the *grep* window at the bottom taking one-fourth of the viewport's height.
  • when searching for a keyword definition, open the definition in a column at the right.
  • more generally when searching for code or browsing code, keep windows with edited buffers on the left column, and open "reference buffers" on the right column.
  • see the man page of the command at the cursor in a new window at the top of the current one.

I know those examples might be against the Kakoune philosophy, but I just try to defend the other side of the spectrum to demonstrate what it can bring in terms of developer experience.

All of those sound pretty great, and I do not think they are against Kakoune's philosphy, on the contrary I think Kakoune should enable those use cases, but not in the way you seem to think about it. I think this kind of rules should probably be configured in the windowing system itself, with Kakoune just hinting at what that new window is expected to be used for. I am not sure how to expose a hint that is going to be accessible from the windowing system, maybe env-vars are enough.

I tend not to have too many issues with window management in my day to day workflow because I usually create 3/4 clients at startup (using the ide command from my config plus and extra new if I got enough room on my screen) then position them (tools at the bottom, docs on the right, main in center and secondary on left).

@lobre
Copy link
Contributor

lobre commented Oct 11, 2023

I think this kind of rules should probably be configured in the windowing system itself, with Kakoune just hinting at what that new window is expected to be used for.

This seems interesting even if I am not sure how to effectively grasp the idea. I'd be glad to have more details about your thinking here.

I usually create 3/4 clients at startup (using the ide command from my config)

This works for some workflows, yes, and it is already great that Kakoune supports this. However, I think it works best for "static" layouts, where you know where things should be located in advance.

In Acme, the size of the window is optimized. So let's say I create an empty buffer in the right column, and then I decide to type "ls -l" and bash-execute this command with mouse button 2 (yes Acme is mouse oriented and mouse 2 "executes" what is being selected). It will create another window for the result, and it will take pretty much the whole height, as my buffer containing "ls -l" is small enough and only contains that line. So it optimizes space.

acme_workflow_1

acme_workflow_2

Then, you also have a notion of "last edited" column. If I execute a grep command from within the same buffer of my "ls -l", the output is shown in the right column below on the same column (g is grep in Plan 9).

acme_workflow_3

From there, I can review my search. I see there are matches in the same file opened on the left column (led.c), so if I click it from the grep results, it will simply focus on the left column where the file is already open. But if I want to open the match from the not-open ex.c file, a new window will be created, but the selected column of this new window will depend if my cursor was before on the left column or the right. If I don't want to clutter my editing session on the left and just quickly review the result of the match, I can first focus my grep result by putting my cursor there, and then click the filename to open it. It will open below the search results.

acme_workflow_4

But if I intend to modify this match in ex.c, I can keep my cursor focused on the left window and the file will open on the left. It allows to keep my files being edited on the left, and the rest on the right.

acme_workflow_5

Again, those are just examples. With this system, Acme allows a lot of different dynamic workflows for users. And I find them handy.

I show Acme here, and by no means do I say that Kakoune should resemble Acme in that regard, nor that it needs such a sophisticated system. But it is more to provide ideas so that inspiration could be taken from tools that do it in an interesting way.

Before I was mostly using a single window to work, but I started to realize that multiwindow workflows are also great.

krobelus added a commit to krobelus/kakoune that referenced this pull request Nov 10, 2023
This is a slightly different approach than mawww#4425.
It allows to create mappings that work in either windowing system like

	map global user c   %{:with-option windowing_placement window new<ret>}
	map global user '"' %{:with-option windowing_placement vertical new<ret>}
	map global user '%' %{:with-option windowing_placement horizontal new<ret>}

Or, when using multiple windowing systems concurrently, you might
want to add mappings like

	map global user t %{:with-option windowing_module tmux new<ret>}
	map global user T %{:with-option windowing_module wayland new<ret>}

TODO: maybe add a reasonable measure of backwards compatibility. 

We could try to keep the alias approach and implement a "with-alias"
command, however that is not powerful enough to capture the two
dimensions (windowing system and placement).
krobelus added a commit to krobelus/kakoune that referenced this pull request Nov 10, 2023
…t in new/terminal commands

Today I can control "terminal" and "new" by changing the terminal
alias but I always need to choose a concrete implementation, like
"tmux-terminal-horizontal", even when there is otherwise no need to
mention tmux in my config.

Allow to configure these by introducing new options for the windowing
system and window placement.

This allows to create mappings that work in either windowing system like

	map global user c   %{:with-option windowing_placement window new<ret>}
	map global user '"' %{:with-option windowing_placement vertical new<ret>}
	map global user '%' %{:with-option windowing_placement horizontal new<ret>}

Or, when using multiple windowing systems concurrently, you might
want to add mappings like

	map global user t %{:with-option windowing_module tmux new<ret>}
	map global user T %{:with-option windowing_module wayland new<ret>}

TODO: maybe add a reasonable measure of backwards compatibility. 

We could try to keep the alias approach and implement a "with-alias"
command, however that approach can only capture both dimensions
(windowing system and placement) if we add tons of commands
like "terminal-horizontal" (with implied windowing system) and
"tmux-terminal" (with implied placement).

Closes mawww#3943, mawww#4425
krobelus added a commit to krobelus/kakoune that referenced this pull request Nov 10, 2023
…t in new/terminal commands

Today I can control "terminal" and "new" by changing the terminal
alias but I always need to choose a concrete implementation, like
"tmux-terminal-horizontal", even when there is otherwise no need to
mention tmux in my config.

Allow to configure windowing system and window placement separately
by introducing dedicated options.

This allows to create mappings that work in any windowing system like

	map global user c   %{:with-option windowing_placement window new<ret>}
	map global user '"' %{:with-option windowing_placement vertical new<ret>}
	map global user '%' %{:with-option windowing_placement horizontal new<ret>}

For windowing systems that don't support all placements, you can wrap
the above in try/catch, falling back on the "window" variant which
is defined for all windowing systems.

When using multiple windowing systems concurrently, you might
want to add mappings like

	map global user t %{:with-option windowing_module tmux new<ret>}
	map global user T %{:with-option windowing_module wayland new<ret>}

---

This changes the default `terminal` alias for some modules. In
particular, instead of delegating to

    iterm-terminal-vertical
    screen-terminal-vertical
    tmux-terminal-horizontal
    wezterm-terminal-vertical

it will now by default delegate to the respective `-window` variant.

Also, this removes the "terminal-tab" alias which was only defined
by the kitty module.

We could try to keep the alias approach and implement a "with-alias"
command, however that approach can only capture both dimensions
(windowing system and placement) if we add tons of commands
like "terminal-horizontal" (with implied windowing system) and
"tmux-terminal" (with implied placement).

Side thought: we could also get rid of the `focus` alias and instead
define

    define-command focus %{
        "%opt{windowing_module}-focus"
    }

Closes mawww#3943, mawww#4425
@krobelus
Copy link
Contributor

here's a slightly different approach to the same end at #5020
One thing I'm not sure about is whether the default new and terminal should create a new window everywhere, or create a split if the windowing systems support that (existing behavior though we are inconsistent here). We can definitely preserve existing behavior and decide later.

krobelus added a commit to krobelus/kakoune that referenced this pull request Nov 13, 2023
…t in new/terminal commands

Today I can control "terminal" and "new" by changing the terminal
alias but I always need to choose a concrete implementation, like
"tmux-terminal-horizontal", even when there is otherwise no need to
mention tmux in my config.

Allow to configure windowing system and window placement independently
by introducing dedicated options.

This allows to create mappings that work in any windowing system like

	map global user c   %{:with-option windowing_placement window new<ret>}
	map global user '"' %{:with-option windowing_placement vertical new<ret>}
	map global user '%' %{:with-option windowing_placement horizontal new<ret>}

For windowing systems that don't support all placements, you can wrap
the above in try/catch to fall back on the "window" variant which is
defined for all windowing systems.

When using multiple (nested) windowing systems, you might want to
add mappings like

	map global user t %{:with-option windowing_module tmux new<ret>}
	map global user T %{:with-option windowing_module wayland new<ret>}

---

This changes the default "terminal" alias for some modules. In
particular, instead of delegating to

    iterm-terminal-vertical
    screen-terminal-vertical
    tmux-terminal-horizontal
    wezterm-terminal-vertical

it will now by default delegate to the respective "-window" variant.
We could maintain backwards compatiblity here by setting the
"windowing_placement" option accordingly, but the new behavior seems
more logical?

Also, this removes the "terminal-tab" alias which was only defined
by the kitty module.

We could try to keep the alias approach and implement a "with-alias"
command, however that approach can only capture both dimensions
(windowing system and placement) if we add tons of commands
like "terminal-horizontal" (with implied windowing system) and
"tmux-terminal" (with implied placement).

Side thought: we could also get rid of the "focus" alias and instead
define

    define-command focus %{
        "%opt{windowing_module}-focus"
    }

Closes mawww#3943, mawww#4425
evannjohnson pushed a commit to evannjohnson/kakoune-ev that referenced this pull request Jan 25, 2024
…t in new/terminal commands

Today I can control "terminal" and "new" by changing the terminal
alias but I always need to choose a concrete implementation, like
"tmux-terminal-horizontal", even when there is otherwise no need to
mention tmux in my config.

Allow to configure windowing system and window placement independently
by introducing dedicated options.

This allows to create mappings that work in any windowing system like

	map global user c   %{:with-option windowing_placement window new<ret>}
	map global user '"' %{:with-option windowing_placement vertical new<ret>}
	map global user '%' %{:with-option windowing_placement horizontal new<ret>}

For windowing systems that don't support all placements, you can wrap
the above in try/catch to fall back on the "window" variant which is
defined for all windowing systems.

When using multiple (nested) windowing systems, you might want to
add mappings like

	map global user t %{:with-option windowing_module tmux new<ret>}
	map global user T %{:with-option windowing_module wayland new<ret>}

---

This changes the default "terminal" alias for some modules. In
particular, instead of delegating to

    iterm-terminal-vertical
    screen-terminal-vertical
    tmux-terminal-horizontal
    wezterm-terminal-vertical

it will now by default delegate to the respective "-window" variant.
We could maintain backwards compatiblity here by setting the
"windowing_placement" option accordingly, but the new behavior seems
more logical?

Also, this removes the "terminal-tab" alias which was only defined
by the kitty module.

We could try to keep the alias approach and implement a "with-alias"
command, however that approach can only capture both dimensions
(windowing system and placement) if we add tons of commands
like "terminal-horizontal" (with implied windowing system) and
"tmux-terminal" (with implied placement).

Side thought: we could also get rid of the "focus" alias and instead
define

    define-command focus %{
        "%opt{windowing_module}-focus"
    }

Closes mawww#3943, mawww#4425
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The built-in multiplexing commands lack flexibility
5 participants