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

Open file in already running Helix (like EmacsClient) #2177

Open
johalun opened this issue Apr 19, 2022 · 18 comments
Open

Open file in already running Helix (like EmacsClient) #2177

johalun opened this issue Apr 19, 2022 · 18 comments
Labels
A-helix-term Area: Helix term improvements C-enhancement Category: Improvements

Comments

@johalun
Copy link

johalun commented Apr 19, 2022

Don't know if this has been discussed already but I couldn't find any issue about it.

I'm a heavy user of Emacs in server mode and emacsclient to open files in an already running Emacs instance (also being able to specify what line to open the file at (for example: hx-client file.rs:55)). I would love to see this feature in Helix.

Thanks!

@johalun johalun added the C-enhancement Category: Improvements label Apr 19, 2022
@the-mikedavis
Copy link
Member

Depends #312

@gdamore
Copy link
Contributor

gdamore commented Oct 13, 2022

I want this for one specific reason.

I find that I have occasionally (frequently!) made the mistake of two instances of helix in different terminals editing the same file. This causes me a problem, because I will then have changes in one of the instances overwrite changes that are made in another. The worst case is when I accidentally switch back to an instance that has an older version of the file open.

I suppose what I'd really to do is open one instance of helix, perhaps with a workspace-specific configuration (e.g. one color theme for work projects, and a different one for personal projects), and then just send commands to that instance.

@Hywan
Copy link

Hywan commented Oct 19, 2022

That would be lovely to get this feature. I'm also a long term Vim and emacs user, and I really enjoy emacs --daemon. I guess it's a neat feature to provide for Helix, even if I know it can be really tricky to get it right.

@Hasnayeen
Copy link

Hasnayeen commented Nov 15, 2022

I want this for a different reason then the one stated above.

I use File Browser/Explorer a lot while coding. Because there is no file tree/browser in helix I use a terminal file manager (joshuto) in a vertical pane in same terminal window and I want to open file from the file manager in the same current helix instance. With this feature I'll be able to have File Browser like experience without helix having one natively.

@j3ka
Copy link

j3ka commented Apr 23, 2023

Hi @Hasnayeen .
I want this feature too for same reason. I created simple script with zellij (or tmux, screen) to emulate this behavior. Maybe this will be useful for You.

#!/bin/bash

# $1 = relative file path
# $2 = session name

tabName="Helix"
sessionName="Helix"

if test -z "$1"
then
  echo "File name not provided"
  exit 1
fi

fileName=$(readlink -f $1) # full path to file

if ! test -z "$2"
then
  sessionName="$2"
fi

if ! pgrep -x helix > /dev/null
then
  zellij -s "$sessionName" action go-to-tab-name $tabName --create
  sleep 0.5
  zellij -s "$sessionName" action write-chars "helix"
  sleep 0.5
  zellij -s "$sessionName" action write 13 # send enter-key
fi

zellij -s "$sessionName" action go-to-tab-name $tabName --create

zellij -s "$sessionName" action write 27 # send escape-key
zellij -s "$sessionName" action write-chars ":open $fileName"
zellij -s "$sessionName" action write 13 # send enter-key
  • start zellij with session name zellij -s {SESSION_NAME}
  • exec script_name /path/to/file [SESSION_NAME]

I use Helix as default session name, that's why second param in script is optional.

@llogiq
Copy link

llogiq commented Apr 25, 2023

I would also like this feature. I've changed my main editor from a combination of VSCode and Geany (linux) / Notepad++ (windows) to helix. Sometimes I have scripts that should open a certain file in an editor. Of course it doesn't matter that much because helix is so lean and my machine so beefy, but it would still be great if I could e.g. edit git commits in helix without a new instance.

@KatsuoRyuu
Copy link

Please shoot me down if im completly off the chart here. But i was thinking this could be done in a more simple way with a combination of a tmpfile and a signal, eg call SIGHUB or SIGUSR1.

So in short if you eg pass a parameter to helix it would create a tmp file with either a shared name or a specific pid and then send a signal (SIGHUB or SIGUSR1) to either the specific pid or the first pid that matches helix. The helix that gets the signal will then load the tmpfile with the new filepaths in and open the files in new buffers.

This means i would not require a server/client implementaiton of helix, and could work with a server/client instance.

@alexjp
Copy link

alexjp commented Jun 6, 2023

nice idea @j3ka !!!

I did something similar:

A zellij layout:

File: git_helix.kdl
layout {
    cwd "/home/alex/dev/src"
    tab name="Git" {
        pane size=1 borderless=true {
            plugin location="zellij:compact-bar"
        }
        pane command="lazygit" borderless=true start_suspended=true
        pane size=2 borderless=true {
            plugin location="zellij:status-bar"
        }
    }
        tab name="Helix" {
            pane size=1 borderless=true {
                plugin location="zellij:compact-bar"
            }
            pane split_direction="vertical" {
                pane focus=true borderless=false size="75%" command="/home/alex/.local/bin/ed"
                pane size="25%" borderless=false command="/home/alex/.local/bin/broot-ide"
            }
        }
}

and broot-ide is a special command line for broot that adds config to open on helix on zellij using the following bin:

File: /home/alex/.local/bin/hx-ide-open
#!/usr/bin/env dash


if test -z "$1"
then
  echo "File name not provided"
  exit 1
fi

fileName=$(readlink -f $1) # full path to file

zellij action move-focus left
zellij action write 27 # send escape-key
zellij action write-chars ":open $fileName"
zellij action write 13 # send enter-key

So now I have a tabs: [git manager] [helix editor and side file manager using broot] and broot opens the file on helix.

One notice though: the helix editor pane on zellij must not be borderless, or screen artifacts happen!

@7flash
Copy link

7flash commented Aug 1, 2023

Following my solution.

  1. spawn kitty window with remote control
kitty -o allow_remote_control=yes -o enabled_layouts=tall
  1. spawn helix tab inside that window
kitty @ launch --type=tab --title "KittyHelix" --keep-focus hx
  1. start local server accepting GET requests and calling :open command in helix through kitty tab
deno run --allow-all ./kitty-hx-server.ts

kitty-hx-server.ts


import { serve } from "https://deno.land/std@0.99.0/http/server.ts";

const server = serve({ port: 8000 });

for await (const req of server) {
  const url = new URL(req.url, `http://${req.headers.get("host")}`);
  const filePath = url.searchParams.get("file");

  if (filePath) {
    const process = Deno.run({
      cmd: ["./kitty-hx-open.sh", filePath],
    });

    await process.status();  // Wait for the script to finish
    process.close();
  }

  req.respond({
    body: "Request processed.\n",
    headers: new Headers({
      "Access-Control-Allow-Origin": "*",
    }),
  });
}

kitty-hx-open.sh

#!/bin/bash

if test -z "$1"
then
  echo "File name not provided"
  exit 1
fi

window_title="KittyHelix"

file_path=$(readlink -f $1) # full path to file

if test -f "$file_path"
then
  kitty @ send-text --match title:$window_title '\E'
  #sleep 0.1
  kitty @ send-text --match title:$window_title ":open $file_path"
  #sleep 0.1
  kitty @ send-text --match title:$window_title '\r'
else
  echo "File does not exist or is not a regular file"
  exit 1
fi
  1. fetch the url externally to trigger opening chosen file
function(filepath) {
    return fetch(`http://localhost:8000/?file=${filepath}`).then(it => it.text());
}

@quantonganh
Copy link
Contributor

quantonganh commented Aug 2, 2023

@Hasnayeen If you are using WezTerm:

  • Use wezterm cli list to list the panes
  • Check if the program in the right pane is hx
  • If yes, send :open $file_path\r to that pane in order to open the file
  • If not, invoke hx as you normally would

#6054 (comment)

@quantonganh
Copy link
Contributor

I find that I have occasionally (frequently!) made the mistake of two instances of helix in different terminals editing the same file. This causes me a problem, because I will then have changes in one of the instances overwrite changes that are made in another. The worst case is when I accidentally switch back to an instance that has an older version of the file open.

@gdamore You can solve this issue by integrating hx with WezTerm using the following steps:

  • Use the command wezterm cli list to list the panes
  • Check if there is any running instance of hx that has same current working directory as the file you want to open
  • If there is an instance matching the conditions, send the command :open $file_path\r to that pane to open the file
  • If there is no matching instance, call hx as usual

Here's the implementation:

#!/usr/bin/env sh

tty=$(tty)
hostname=$(hostname | tr '[:upper:]' '[:lower:]')
pwd=$(pwd)
file_path=$1

pane_id=$(wezterm cli list --format json | jq --arg tty "$tty" --arg opening_cwd "file://$hostname$pwd" --arg file_path "file://$hostname$file_path" -r '.[] | .cwd as $running_cwd | select((.tty_name != $tty) and (.title | startswith("hx")) and (($opening_cwd | contains($running_cwd)) or ($file_path | contains($running_cwd)))) | .pane_id')
if [ -z "$pane_id" ]; then
    ~/.cargo/bin/hx $1
else
    if [ -n "$file_path" ]; then
        echo ":open ${file_path}\r" | wezterm cli send-text --pane-id $pane_id --no-paste
    else
        echo ":open ${pwd}\r" | wezterm cli send-text --pane-id $pane_id --no-paste
    fi
    wezterm cli activate-pane --pane-id $pane_id
fi

@chtenb
Copy link
Contributor

chtenb commented Sep 1, 2023

If you're using nushell, the following works well for me. (Tested on windows)

First configure broot as a filepicker: (enter prints the path to stdout)

[[verbs]]
# print path and exit broot
invocation = "print_path"
keys = ["enter"]
shortcut = "pp"
apply_to = "file"
leave_broot = true
internal = ":print_path"

Then configure space-e as opening the file picker (in helix conf):

[keys.normal.space]
e = """
:sh echo `echo $':open "(broot)"\r' | wezterm cli send-text --pane-id (wezterm cli get-pane-direction left); exit\r` 
  | wezterm cli send-text --pane-id (wezterm cli split-pane --right --percent 33) --no-paste
"""

What this does is open a terminal pane to the right with broot, you pick any file/folder and on pressing enter it closes the pane and loads the file into helix.

@chriselrod
Copy link

chriselrod commented Oct 2, 2023

@quantonganh I am always getting a j at the end for some reason, and the carriage return isn't being processed.
That is,
script foo.txt
gives me an open command with
:open foo.txt\rj
instead of the expected result of opening foo.txt.

I do not know where the j is coming from. It isn't part of the echoed string, and removing --no-paste gets rid of it, but then of course the string gets inserted into the text, rather than into the command. Similar for removing the colon so that it is no longer interpreted as a command.

The zellij solution involving writing 27 and 13, however, seems to work.

Replacing the echo pipe with passing the argument directly avoids the extra js, but I can't get the carriage return to work; it always appears.

@quantonganh
Copy link
Contributor

@chriselrod Could you please try this:

$ echo -e ":open foo.txt\r" | wezterm cli send-text --pane-id 1 --no-paste

@mahor1221
Copy link

mahor1221 commented Dec 23, 2023

I've done something similar with tmux and vifm (the side pane is toggle-able):

2023-12-23_07-24-31

Here is the configurations: https://github.com/vifm/vifm/tree/master/data/plugins/editor

@client-side96
Copy link

@chriselrod I am having the same issue with the j being appended when piping the echo command and the carriage return not working when using the inline command. Did you find a solution for this?

@chriselrod
Copy link

@chriselrod I am having the same issue with the j being appended when piping the echo command and the carriage return not working when using the inline command. Did you find a solution for this?

No, I discovered kakoune shortly after making that comment and have been using it since.
It is built around the client/server model, assuming you are using an external window manager such as tmux, zellij, or your os window manager to manage your windows. This is what I wanted, and kak is otherwise similar to helix, making it an obvious switch.

@dj8yfo
Copy link

dj8yfo commented Mar 6, 2024

File: /home/alex/.local/bin/hx-ide-open
...

this script can be combined with gret tool as well : https://github.com/dj8yfo/gret/tree/hx_ide_open

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-helix-term Area: Helix term improvements C-enhancement Category: Improvements
Projects
None yet
Development

No branches or pull requests