How can I enable tab-completion for `#` path options to HTTPie in fish? - fish

HTTPie accepts paths as arguments with options that include the # sign. Unfortunately, they don't seem to work with shell completions in fish. Instead, the option is treated as an opaque string.
To stick with the file upload example from the HTTPie documentation with a file at ~/files/data.xml, I would expect to be able to tab complete the file name when typing:
http -f POST pie.dev/post name='John Smith' cv#~/files/da<TAB>
However, no completion is offered.
I have installed the completions for fish from the HTTPie project and they work for short and long arguments. This file does not specify how to complete the # arguments though.
In addition, I looked into specifying my own completions but I am not able to find a way of getting to work file completions with the arbitrary prefix.
How could I implement a completion for these path arguments for HTTPie?

Currently, the fish completions for HTTPie do not have completion for file path arguments with #. There is a more general GitHub Issue open about this.
If this is something you'd like to work on, either for yourself or for the project, you might be able draw some inspiration for the fish implementation from an HTTPie plugin for zsh+ohmyzsh that achieves your desired behaviour.

I managed to get the tab completion of the path arguments working with some caveats.
This adds the completion:
complete -c http --condition "__is_httpie_path_argument" -a "(__complete_httpie_path_argument (commandline -t))"
With the following functions:
function __is_httpie_path_argument
set -l arg (commandline -t)
__match_httpie_path_argument --quiet -- $arg
end
function __match_httpie_path_argument
string match --entire --regex '^([^#:=]*)(#|=#|:=#)(.*)$' $argv
end
function __complete_httpie_path_argument
__complete_httpie_path_argument_helper (__match_httpie_path_argument -- $argv[1])
end
function __complete_httpie_path_argument_helper
set -l arg $argv[1]
set -l field $argv[2]
set -l operator $argv[3]
set -l path $argv[4]
string collect $field$operator(__fish_complete_path $path)
end
The caveat is that this does not expand any variables nor the tilde ~. It essentially only works for plain paths — relative or absolute.

Related

How can I ensure my autocompleted spaces are fed into my function properly?

I'm using zsh, and am trying to write a function to operate on a URL and a pathname:
function my-function
{
somecommand --url $1 $(readlink -f $2)
}
(to complicate things somewhat, the function actually uses sh syntax, as it is sourced from my ~/.zshrc using a trick like this). The readlink is there to expand symlinks and ensure directories such as . are evaluated correctly (the directory name is stored for later use by somecommand).
When I type a command from the command-line like this:
my-function http://example.org/example /tmp/myexampledirectory
... it works fine, even if I autocomplete the directory name. However, if the directory name contains spaces, zsh completes it like this:
my-function http://example.org/example /tmp/My\ Example\ Directory
For most "normal" commands (cp, mv, etc.) that never seems to cause a problem. However, in my case, somecommand sees $2 as only being /tmp/My - presumably the rest is seen as another argument.
How can I avoid this situation? I would prefer not to alter the standard zsh autocompletion, but rather find a way for my function to handle this.
The zsh completion system works very well here, and the solution is very simple, just put double-quotes around the readlink argument in the script:
somecommand --url $1 $(readlink -f "$2")
The point is that without quotes readlink removes backslashes which escape whitespaces. Compare three results:
1. Without backslashes and quotes readlink -f assumes that there are three different files/directories (with default path in current directory) and produces
$ readlink -f /tmp/My Example Directory
/tmp/My
/home/jimmij/Example
/home/jimmij/Directory
2. With escaping backslashes but without quotes readlink -f understands that there is only one directory, but removes backslashes from output, so that somecommand takes three separate arguments
$ readlink -f /tmp/My\ Example\ Directory
/tmp/My Example Directory
3. With backslashes and with double-quotes readlink -f gives the output with backslashes what is (most probably) expected by somecommand
$ readlink -f "/tmp/My\ Example\ Directory"
/tmp/My\ Example\ Directory
BTW, as a rule of thumb: if there are any problems with whitespaces in the shell-like scripts (bash, zsh, whatever) the first thing to play with is different quotation marks around variables.

Oh-my-zsh aliases do not autocomplete

I am a bit out of my wits researching this... and I just have to ask.
I have oh-my-zsh on my Mavericks machine and have everything updated. I also have Xcode and Brew. All updated. According to this page: https://github.com/robbyrussell/oh-my-zsh/wiki/Cheatsheet am I not supposed to just type, say: "g" [tab] and get "git"? or type "md" [tab] and get "mkdir -p"? Right now I just get a list of options I can tab through (or arrow through)... I thought it would autocomplete. What am I missing?
I have a feeling it might be related to my $PATH but that is where I also get confused... where should it point to?
I greatly appreciate and enlightenment.
# Path to your oh-my-zsh configuration.
#ZSH=$HOME/.oh-my-zsh
export ZSH=$HOME/.oh-my-zsh
# Set name of the theme to load.
# Look in ~/.oh-my-zsh/themes/
# Optionally, if you set this to "random", it'll load a random theme each
# time that oh-my-zsh is loaded.
#ZSH_THEME="af-magic"
ZSH_THEME="agnoster"
# Set to this to use case-sensitive completion
# CASE_SENSITIVE="true"
# Comment this out to disable weekly auto-update checks
# DISABLE_AUTO_UPDATE="true"
# Uncomment following line if you want to disable colors in ls
# DISABLE_LS_COLORS="true"
# Uncomment following line if you want to disable autosetting terminal title.
# DISABLE_AUTO_TITLE="true"
# Uncomment following line if you want red dots to be displayed while waiting for completion
COMPLETION_WAITING_DOTS="true"
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Example format: plugins=(rails git textmate ruby lighthouse)
plugins=(git textmate sublime zsh-syntax-highlighting)
source $ZSH/oh-my-zsh.sh
#export PATH=/usr/local/bin:/usr/local/sbin:/usr/local/git/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/X11/$
#export PATH=$HOME/bin:/usr/local/bin:$PATH
export PATH=/usr/local/bin:$PATH
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
zstyle ':completion:*' list-prompt ''
zstyle ':completion:*' select-prompt ''
autoload -Uz compinit
compinit
Aliases are essentially just short names for commands. Before executing a command zsh internally replaces aliases by their values. But by default aliases are not expanded when using completion (Tab), they are handled just like any other command.
For example:
alias ll='ls -l'
alias la='ls -al'
If you now type lTab, zsh will present you every command starting with an l, including the aliases ll and la. If you type llTab it will probably just add an space after ll (assuming there are no other commands starting with ll).
When you run ll somedir it does the exact same thing as ls -l somedir. You can even add other options of ls: ll -t somedir runs ls -l -t somedir.
That being said, if you want to expand aliases when typing Tab, zsh can do so.
There are two ways:
You can call the _expand_alias widget. In emacs mode (bindkey -e) this is bound to ^Xa (press Control+X then A).
You can add _expand_alias to the completer style. It seems that oh-my-zsh does not change this style from its default value, so adding
zstyle ':completion:*' completer _expand_alias _complete _ignored
to your ~/.zshrc should work.
(To be save you can print the current setting with zstyle -L ':completion:*' completer, _expand_alias has to come before _complete)
If you now type llTab, zsh will replace it with ls -l immediatelly.
Note: in both cases the cursor has to be in or just after the alias for the replacement to happen. This also means you have to type the whole alias or backspace if automatically completed (_completer adds a space after successful completion)

Checking if a file is a text file without using -T?

Title is pretty self explanatory, are there file testing functions in perl or is there a built in module that allows file testing operations?
This is a non-issue as -T like all of the file test operators are perl builtins.
They are documented here: perldoc -X
-X FILEHANDLE
-X EXPR
-X DIRHANDLE
-X
A file test, where X is one of the letters listed below. This unary operator takes one argument, either a filename, a filehandle, or a dirhandle, and tests the associated file to see if something is true about it. If the argument is omitted, tests $_ , except for -t , which tests STDIN. Unless otherwise documented, it returns 1 for true and '' for false, or the undefined value if the file doesn't exist. Despite the funny names, precedence is the same as any other named unary operator.
...
-T File is an ASCII text file (heuristic guess).
-B File is a "binary" file (opposite of -T).
The "file test" functions available in Perl are part of the programming language itself. Based on what you're saying and from the comments on this page, it may be that you have been "asked not to use external commands" because someone thinks that the -T flag is relying on something that belongs to the underlying environment and not the Perl language.
-T is part of the -X file test unary operators which are inherent to Perl:
http://perldoc.perl.org/functions/-X.html
Underlying the -T operator (specifically) is the function pp_fttext, which lives in pp_sys.c. These are part of the underlying code that comprises Perl, and you can verify this by looking in the root directory of the Perl source distribution:
http://www.perl.org/get.html
It may be the only way to do what you were originally asking (how to do this without -T) might be to do what you were asked not to do (use something external to Perl to perform the test).

Running a script in bash

I have a script in one of my application folders.Usually I just cd into that locatin in Unix box and run the script e.g.
UNIX> cd My\Folder\
My\Folder> MyScript
This prints the required result.
I am not sure how do I do this in Bash script.I have done the following
#!/bin/bash
mydir=My\Folder\
cd $mydir
echo $(pwd)
This basically puts me in the right folder to run the required script . But I am not sure how to run the script in the code?
If you can call MyScript (as opposed to ./MyScript), obviously the current directory (".") is part of your PATH. (Which, by the way, isn't a good idea.)
That means you can call MyScript in your script just like that:
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
As I said, ./MyScript would be better (not as ambiguous). See Michael Wild's comment about directory separators.
Generally speaking, Bash considers everything that does not resolve to a builtin keyword (like if, while, do etc.) as a call to an executable or script (*) located somewhere in your PATH. It will check each directory in the PATH, in turn, for a so-named executable / script, and execute the first one it finds (which might or might not be the MyScript you are intending to run). That's why specifying that you mean the very MyScript in this directory (./) is the better choice.
(*): Unless, of course, there is a function of that name defined.
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
I would rather put the name in quotes. This makes it easier to read and save against mistakes.
#!/bin/bash
mydir="My Folder"
cd "$mydir"
echo $(pwd)
./MyScript
Your nickname says it all ;-)
When a command is entered at the prompt that doesn't contain a /, Bash first checks whether it is a alias or a function. Then it checks whether it is a built-in command, and only then it starts searching on the PATH. This is a shell variable that contains a list of directories to search for commands. It appears that in your case . (i.e. the current directory) is in the PATH, which is generally considered to be a pretty bad idea.
If the command contains a /, no look-up in the PATH is performed. Instead an exact match is required. If starting with a / it is an absolute path, and the file must exist. Otherwise it is a relative path, and the file must exist relative to the current working directory.
So, you have two acceptable options:
Put your script in some directory that is on your PATH. Alternatively, add the directory containing the script to the PATH variable.
Use an absolute or relative path to invoke your script.

diffstrings.py : how do you specify path arguments?

I am trying to use diffstrings.py from Three20 on my iPhone project, and I can't find the proper format for the path arguments (as in "Usage: diffstrings.py [options] path1 path2 ...").
For example, when I run the script in my Xcode project directory like this
~/py/diffstrings.py -b
it analyzes just the main.m and finds 0 strings to localize,
then it diffs against existing fr.lproj and others, and finds that thes contain "obsolete strings".
Can anyone post examples of successful comand line invocations of diffstrings.py, for options -b, -d and -m?
Taking a quick look at the code here http://github.com/facebook/three20/blob/master/diffstrings.py I see that if you don't specify any command line options, it assumes you mean the directory wherever the script lives in. So the option is to either copy .py file to where your .m files are, or simple use the command
~py/diffstrings.py -b .
That is, give the current directory (.) as the path argument.