Is there a way to add a command to neovim that can be called as `:command`? - neovim

What I would like to archieve is to be able to use :< shell command and add the output to the shell command to the cursor's position in neovim.
It seems I could use :redir to archieve this functionality and wrap it in to a function.
Is there a way to associate a [neo]vim function to :command?

A command can't return value. Hence a command is not an expression. And in particular, commands never can be "nested" one into another, like function calls. Cf. Shell scripting, for example.
In principle, there are some tricks, like a builtin function that accepts command name, runs it, and returns output as string value. But this is rather "convenient redir", not "syntax breaker".
To add external tool output into cursor position use, for example,
put=system('blah blah')
This is legal, as (some of) commands may accept expressions, including function calls.
Make sure to escape "bars" and "double quotes" though, as (sometimes) they are special in VimScript.

Related

Make & show the same information as a command prompt

In my previous questions here on stack we determined my command should run like this.
(& C:\Gyb\Gyb.exe --email $DestinationGYB --action restore --local-folder $GYBFolder --label-restored $GYBLabel --service-account)
The problem with this is if I run that same command in a command prompt I would see a bunch of status information.
When I run the command as above all I see in VSCode is it ran that line and its waiting. How can I make it show me like the command prompt without opening a new window?
here is GYB
https://github.com/jay0lee/got-your-back
Remove the parentheses () around your command if you want to see the output at the same time. Otherwise, this behavior is expected and is not unique to the VSCode terminal.
The group-expression operator () is used to control the order of which code is executed in PowerShell. Expressions are evaluated like order of operations (re: PEMDAS) in Mathematics, the inner-most parentheses get evaluated first. You can also use the group-expression operator to invoke a property or method from the returned expression in the group.
The problem is, group-expressions don't output to the parent level directly, that only happens when the group-expression is done executing. So when you have something that can run for several minutes or even hours like gyb.exe, you don't see that output until the command exits and execution continues.
Contrast this to running outside of the group-expression; as STDOUT is written to the success stream the success stream is immediately written to console as it comes. There is no additional mechanism you are proxying your output through.
Note: You will experience nearly the same behavior with the sub-expression operator $() as well, although do not conflate sub-expressions and group-expressions as they serve different purposes. Here is a link to the official explanation of theGrouping Operator ( ), the Subexpression Operator `$( ) is explained immediately below it.

Is there a good place in .vim folder to store text filters?

I would like to create a filter folder, best inside .vim and be able to run a text filter just with one file name:! filter.pl
I put up a Perl text filter to change all special Characters in a LaTeX Math Formula, which is running fine so far - only problem it is running on the whole line not the selected formula, but I can live with it ...
#!/usr/bin/perl -np
use strict;
use warnings;
# this filter transforms all special characters in Mathformular for LaTeX
s/\\/\\backslash /g;
s/([\$\#&%_{}])/\\$1/g;
But to call this filter is cumbersome
: '<,'>!"/Users/username/Library/Mobile Documents/com~apple~CloudDocs/my_vim_cheat_sheet/perl_filter.pl"
Apple put in the path to the iCloud a white space, so I have to put "" around! Where I put a collection of text filters?
Thank you for your answers
marek
You can safely create a subfolder with any name different from ones Vim uses itself (see :h 'rtp'). So this is ok:
:*!$HOME/.vim/filters/perl_filter.pl
Also Vim has a predefined interface for a general purpose filter called 'equalprg'. To make use of it simply set a global-local (i.e. both set and setlocal are meaningful) option equalprg to a fully qualified name of your script. Then hit = in visual mode to apply filter (or ={motion} in normal mode). (Read :h 'equalprg' :h =).
If you need several filters at once, and switching equalprg is not convenient, you can still try different options to reduce typing.
For example, mappings, such as
vnoremap <Leader>f :!/path/to/my/filter<CR>
Then hitting \f (or whatever is your "leader" key set) in the visual mode will result in the executing :'<,'>!/path/to/my/filter (note that the visual selection will be applied automatically).
Another attempt is to set a dedicated environment variable (which will be inherited by all child processes including shell(s). For example,
:let $filters = '~/.vim/filters'
:*!$filters/myfilter.pl
Of course, you can put those set equalprg=... vnoremap ... let $filters=... etc.etc. in your vimrc.
I would like to create a filter folder, best inside .vim and be able to run a text filter just with one file name :! filter.pl
Simply add the script to somewhere within your $PATH. Or, if you really only intend to use that from within Vim, then add that directory to your $PATH in your .vimrc, so you have it available there.
For example, if you'd like to use ~/.vim/scripts for your external Perl or shell scripts, you can use this in your ~/.vimrc:
call setenv('PATH', expand('~/.vim/scripts').':'.$PATH)
After that, you can simply use :'<,'> !filter.pl to run it. And Tab completion will work with the name of the script, type :!fil<Tab> and Vim will complete it to filter.pl, assuming it's a unique prefix.
The snippet above for your .vimrc has one minor issue, that if you :source your .vimrc during Vim runtime, it will keep adding the entry to $PATH multiple times. That doesn't typically break anything, only the entry will become longer, you might run into variable length issues.
You can fix it by checking whether that's present in path or not before updating it, perhaps with something like:
let scripts_dir = expand('~/.vim/scripts')
if index(split($PATH, ':'), scripts_dir) < 0
call setenv('PATH', scripts_dir.':'.$PATH)
endif
But also, about this:
I put up a Perl text filter to change all special Characters in a LaTeX Math Formula
s/\\/\\backslash /g;
s/([\$\#&%_{}])/\\$1/g;
Consider writing that in Vim instead.
In fact, almost the same syntax will work as a Vim function:
function! EscapeLatexMathFormula()
s/\\/\\backslash /eg
s/\([$#&%_{}]\)/\\\1/eg
endfunction
You can call it on a range, with:
:'<,'>call EscapeLatexMathFormula()
Calling it without a range will affect the current line only.
You can also make it into a command, with:
command! -range EscapeLatexMathFormula <line1>,<line2> call EscapeLatexMathFormula()
In which case you can simply use:
:'<,'>EscapeLatexMathFormula
You can use tab-completion for the function and command names (though, of course, you can pick shorter names if you'd like, as well.)
Note that user-defined command names need to start with an uppercase letter. Function names can start with an uppercase letter too (there are more options for function names, but making this global with an uppercase is probably the easiest here.)

What fish function controls completion of filenames, and how can I change it?

I am trying to alter the standard logic used by fish to find filename completions. In particular, I want fish not to consider any filename that ends in a tilde (~) character, as these are emacs backup files and are not interesting.
I had assumed that the list of possible completions would be provided by a fish function, which I could then edit to remove the ones ending in tildes. But I cannot find the function. I have looked in the documentation at fishshell.com, and I have also tried functions | grep complete. What function should I be editing?
Unlike most completions file name completions is not implemented as a function; it's baked into the C++ code. See the completer_t::complete_param_expand() method in src/complete.cpp. If you can make a cogent argument for how this type of customization would be implemented I'd encourage you to open an issue.
P.S., Note that functions will not show private functions unless you invoke it as functions -a. I mention this because many completion functions are marked private by beginning their name with an underscore.

avoiding exploit in perl variable extrapolation from file

I am optimizing a very time/memory consuming program by running it over a dataset and under multiple parameters. For each "run", I have a csv file, "setup.csv" set up with "runNumber","Command" for each run. I then import this into a perl script to read the command for the run number I would like, extrapolate the variables, then execute it on the system via the system command. Should I be worried about the potential for this to be exploited, (I am worried right now)? If so, what can I do to protect our server? My plan now is to change the file permissions of the "setup.csv" to read only and ownership to root, then go in as root whenever I need to append another run to the list.
Thank you very much for your time.
Run your code in taint mode with -T. That will force you to carefully launder your data. Only pass through strings that are ones you are expecting. Do not launder with .*, but rather check against a list of good strings.
Ideally, there a list of known acceptable values, and you validate against that.
Either way, you want to avoid the shell by using the multi-argument form of system or by using IPC::System::Simple's systemx.
If you can't avoid the shell, you must properly convert the text to pass to the command into shell literals.
Even then, you have to be careful of values that start with -. Lots of tools accept -- to denote the end options, allowing other values to be passed safely.
Finally, you might want to make sure the args don't contain the NUL character (\0).
systemx('tool', '--', #args)
Note: Passing arbitrary strings is not possible in Windows. Extra validation is required.

Read in command line arguments from DrRacket

How do I detect what command line arguments where given when a script is run with racket? That is, the equivalent of sys.argv in Python, args[] in Java, etc...
You have these choices (you can look them all up in the docs for more info):
current-command-line-arguments -- a vector holding the command line arguments
You can start a script with the -m flag, which will require the file and look for a provided main function, then apply it on the command-line arguments (as a list of strings)
Or you can require racket/cmdline which provides a macro that can be used to define several flags in a convenient way.