helix-editor / helix

A post-modern modal text editor.
https://helix-editor.com
Mozilla Public License 2.0
33.3k stars 2.47k forks source link

Simple :sh command substitutions #3134

Open aikomastboom opened 2 years ago

aikomastboom commented 2 years ago

It would be nice to be able to reference editor information on the :sh line.

Things like for example:

subs description
$fn filename (= $bn.$ex)
$bn basename
$ex extension
$fp full path
$rp relative path (to .git root?)
$ln line number

to be able to execute things like:

:sh gh browse $fn:$ln

Of course above example is just a starting point to get the idea across.

the-mikedavis commented 2 years ago

It's a bit of a nit but I'd prefer more explicit names like $file, $line rather than two-character shortcuts. They're not very discoverable and are only marginally easier to type

aikomastboom commented 2 years ago

Indeed, whole words as tokens is indeed nicer, especially when combined with completion to speed up the typing.

Also it occurred to me the $ prefix may not be such a great idea, as it commonly used by sh itself. What about # as a tokenizer?

the-mikedavis commented 2 years ago

I imagine this would be implemented by setting environment variables for the shell command and then the shell command would interpret them - so $var for unix-like and %var% or whatever it is for windows - rather than a search-and-replace or templating language rendered ahead of time.

aikomastboom commented 2 years ago

Ah, yes, of course we have full control over the env space at execution time.

Still would like to have some help typing the longer vars though ;)

AceofSpades5757 commented 2 years ago

I think longer variable names also follows Helix' way of doing things. I imagine that aliases would be implemented in the future with more configuration options.

Instead of environment variables, configuration variables could be used as well, for the project/.helix directory.

aikomastboom commented 2 years ago

Revised table:

env description
$HX_FILENAME filename
$HX_BASENAME basename
$HX_FILE_EXT file extension
$HX_PATH full absolute path
$HX_RELATIVE_PATH relative path (to .git root? or $CWD)
$HX_LINE line number
$HX_COLUMN cursor pos (on line)
the-mikedavis commented 2 years ago

I think we should start small: we probably only need file, line and column. The others can be derived in the shell with basename/extname/dirname/pwd/etc (I'm sure windows has equivalents, right? 🙃)

aikomastboom commented 2 years ago

I would suggest keeping $HX_PATH as this is a known fact of the editor, not having it would add unneeded clutter to constructing an arbitrary command line.

aikomastboom commented 2 years ago

... (I'm sure windows has equivalents, right? 🙃)

🕵️‍♂️ No clue either, haven't used it in a long time.. but I certainly hope command.com got improved upon. 🤔 Is Cygwin still around?

AceofSpades5757 commented 2 years ago

Windows has the capacity to derive the same values and Cygwin, or similar programs, are available. I'd recommend WSL if you need Linux capabilities, though, compared to Cygwin or other alternatives.

devyn commented 2 years ago

I kind of like the way Kakoune does it. They have interpolations like %val{bufname} (access a value) or %opt{filetype} (access an option), but some common things are also in registers, which Helix already supports, but they just have more of them. The % register contains the buffer name, so you can always <C-r> % to get the buffer name.

On that note I'd love to be able to access the regex captures that way too - registers 0-9 in Kakoune are used for the capture groups. So you can s pattern <ret> c <C-r> 1 <esc> to replace with capture group 1 for example.

AceofSpades5757 commented 2 years ago

@devyn Ah, that's an interesting take on it. Looks pretty nice. I wonder if there's a common Rust library that essentially does the same thing.

Kakoune Commands (Prompt) Kakoune Prompt Expansion

The only expansions I can think of with Vim is % and #, but I'm really not a fan of how unintuitive it feels. I'm sure there are other things that I'm simply not aware of, given the docs and implementation.

mindreader commented 2 years ago

The percent register comes from vim. I have a habit of constantly in vim using adhoc shell commands like eg. !git diff %. (diff of the current file), !ls %:s/src/ (list of a subdirectory of the current file's location). And I'm kind of missing it.

Bonus points for keeping it simple to type.

georgesboris commented 1 year ago

it would be great to define custom variables like these as part of my config as well - I'm currently using kitty remote to trigger tests, file browser, etc. however, every command I build has to begin with 40 characters of setup before I get to my 6 character's command and sh apparently doesn't get access to my shell's aliases so I can't make these shorter outside helix as well...

e.g.

[keys.normal]
C-f = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=overlay lf"
C-t = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab mix test"
C-T = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab pnpm test"

vs

[keys.normal]
C-f = ":sh $HX_OVERLAY lf"
C-t = ":sh $HX_TAB mix test"
C-T = ":sh $HX_TAB pnpm test"

[shell]
OVERLAY = "kitty @ launch --no-response --copy-env --hold --cwd=current --type=overlay"
TAB = "kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab"
sebashwa commented 1 year ago

It could potentially be useful to also provide context information like the class / function path names relative to the current cursor position e.g. to trigger single tests for some test runners. See also https://github.com/helix-editor/helix/discussions/5014#discussioncomment-4346933.

sporto commented 1 year ago

I would love something like this to be able to make a copy of the current file I am working on in the same directory. e.g.

Given I have a/b/one.txt opened, I will like to create a/b/two.txt with something like

:w $pwd/two.txt
rcorre commented 1 year ago

to be able to execute things like:

:sh gh browse $fn:$ln

This is the exact use case I came here looking for. It would be nice to support a multiline selection (like GBrowse from vim-fugitive). Would it be reasonable to add $HX_LINE_END and $HX_COLUMN_END?

I'm assuming that the LINE/COLUMN vars refer only to the primary selection, and other cursors are ignored, right? Or do we run the command separately on each selection?

edrex commented 1 year ago

Not being able to have commands parameterized by either context variables like the current file or the output of a shell command is blocking so many workflow integration tasks for me (stuff like keys.normal."\\".j = ":o ~/journal/%sh{my-date-alias}.md" using the syntax of #3393), but I don't have Rust chops (yet) and haven't wanted to be a "me too" clogging that PR's thread.

I think simple and well-designed shell-integration features like this, the existing shell_* family of commands, and a good implementation of job-control-based tag-teaming with other apps like ranger, as laid out in kakoune/wiki: Integrating Other CLI Apps (I'll probably do this and document it soon, if someone else doesn't) can take care of a large portion of the use cases a lot of folks are thinking of when they go looking for a "Plugin system", leaving the real eventual plugins API (#3806) the remaining usecases that require substantial, nontrivial, and deep integration with Helix. Thanks for listening to my TED talk.

mostafaqanbaryan commented 11 months ago

This is a really important feature for using helix. Apparently https://github.com/helix-editor/helix/pull/6979 got stuck. I hope it'd be merged soon.

CAESIUS-TIM commented 10 months ago

Is there a way to copy %(document path) to *(system path) for a temporary solution? Thanks!

finalclass commented 7 months ago

This one is the only issue that is keeping me from switching to helix. The thing is that helix has great built in features however there are few things which are non standard that I heavily rely on. Unfortunately helix is not giving us any way to integrate custom stuff. Adding a way to pass information about current selection (or current cursor positions) to a shell script would solve 90% of the issues.

cpdean commented 5 months ago

The PR that has been open for a while to implement this appears to be stuck on some tricky parsing issues. I wonder if we can sidestep the need to figure out the ideal variable expansion implementation by having :sh set a bunch of environment variables instead? That way we can at least write scripts that use the environment variables instead of using positional arguments. Even if the script is just

#!/bin/bash

command_that_needs_positional_args $HELIX_FILENAME $HELIX_LINE_NUMBER $HELIX_COLUMN_NUMBER

Compared to the command parsing issues of https://github.com/helix-editor/helix/pull/6979, it would be both simpler as well as not introducing any changes that would be broken when that PR eventually merges.

quantonganh commented 5 months ago

Adding a way to pass information about current selection to a shell script would solve 90% of the issues.

@finalclass: Have you tried yank_main_selection_to_clipboard then pipe it to a shell script by using :sh, :insert-output, ...:

[keys.select.";"]
q = ["yank_main_selection_to_clipboard", "delete_selection", ":insert-output echo `pbpaste` | quicktype -l go"]

or current cursor positions

WezTerm has a feature to get the content of a pane. In the mean time, would you like to give it a try?

status_line=$(wezterm cli get-text | rg -e "(?:NORMAL|INSERT|SELECT)\s+[\x{2800}-\x{28FF}]*\s+(\S*)\s[^│]* (\d+):*.*" -o --replace '$1 $2')
filename=$(echo $status_line | awk '{ print $1}')
line_number=$(echo $status_line | awk '{ print $2}')

https://quantonganh.com/2023/08/19/turn-helix-into-ide.md#running-code

rcorre commented 5 months ago

Have you tried yank_main_selection_to_clipboard then pipe it to a shell script by using :sh, :insert-output, ...:

@quantonganh I'm not sure how this is different from :pipe. The issue is that you have no positional information, which is necessary for things like gh.

quantonganh commented 5 months ago

Sorry for breaking up the @finalclass's question into two smaller questions.

@rcorre I meant that:

  1. To pipe the current selection to a shell script, we can use: yank_main_selection_to_clipboard, then :pipe, :insert-output, ...

  2. To get the current cursor positions, I'm using wezterm cli get-text to parse the status line to get the filename and the line number. Then we can open it in the browser by using something like:

  "open")
    remote_url=$(git config remote.origin.url)
    if [[ $remote_url == *"github.com"* ]]; then
      gh browse $filename:$line_number
    else
      current_branch=$(git rev-parse --abbrev-ref HEAD)
      open $(echo $remote_url | sed -e 's|:|/|' -e 's|\.git||' -e 's|git@|https://|')/-/blob/${current_branch}/${filename}#L${line_number}
    fi
    ;;
rcorre commented 5 months ago

My bad @quantonganh, I didn't read closely enough. It would still be great to have a non-terminal specific solution, but that's a neat workaround!

7flash commented 3 weeks ago

it would be great to define custom variables like these as part of my config as well - I'm currently using kitty remote to trigger tests, file browser, etc. however, every command I build has to begin with 40 characters of setup before I get to my 6 character's command and sh apparently doesn't get access to my shell's aliases so I can't make these shorter outside helix as well...

e.g.

[keys.normal]
C-f = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=overlay lf"
C-t = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab mix test"
C-T = ":sh kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab pnpm test"

vs

[keys.normal]
C-f = ":sh $HX_OVERLAY lf"
C-t = ":sh $HX_TAB mix test"
C-T = ":sh $HX_TAB pnpm test"

[shell]
OVERLAY = "kitty @ launch --no-response --copy-env --hold --cwd=current --type=overlay"
TAB = "kitty @ launch --no-response --copy-env --hold --cwd=current --type=tab"

In your example, how can you reference the file currently opened in helix active buffer? Let's say you don't want to do "pnpm test" over all the files but just current one.