zsh-users
 help / color / mirror / code / Atom feed
* ZLE Widget: Insert last word (except &)
       [not found] <20000711140506.5143gmx1@mx14.gmx.net>
@ 2000-07-11 17:29 ` Christoph Lange
  2000-07-11 22:05   ` Vincent Lefevre
  2000-07-12  8:26   ` Bart Schaefer
  0 siblings, 2 replies; 8+ messages in thread
From: Christoph Lange @ 2000-07-11 17:29 UTC (permalink / raw)
  To: zsh-users

Hi there,

  I found it annoying that the widget insert-last-word inserts `&' if the
previous command was a background job. I'd rather like the last word
*before* `&' to be inserted. So I wrote a custom widget:

smart-insert-last-word() {
  emulate -L zsh
  setopt extendedglob

  if [[ -n "$NUMERIC" ]]
  then
    zle insert-last-word -n $NUMERIC
  else
    lastcmd=`fc -n -l -1`
    lastcmd=${lastcmd%%[[:space:]]#}

    if [[ $lastcmd[$#lastcmd] == '&' && $lastcmd[$#lastcmd-1] != '\' ]]
    then
      zle insert-last-word -n 2
    else
      zle insert-last-word
    fi
  fi    
}

zle -N smart-insert-last-word

bindkey "^[." smart-insert-last-word
bindkey "^[_" smart-insert-last-word

If any numeric argument is given, the original function is called with
that argument. Otherwise, the previous command ist determined. If it
ends with `&', insert-last-word is invoked with an argument of 2,
which inserts the last but one word.

Example:

% myeditor *.txt &
% cp _                # press [Alt+.], _ is the cursor
% cp *.txt_           # result

Hope you find it useful.

Christoph

-- 
   o      o     o    o     o    <o     <o>    o>    o
  .|.    \|.   \|/   //    X     \      |    <|    <|>
   /\     >\   /<    >\   /<     >\    /<     >\    /<
Mr. Asciihead learns the Macarena
Christoph Lange, langec@gmx.de, http://www.cul.de/home/yaph/, ICQ #51191833


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-11 17:29 ` ZLE Widget: Insert last word (except &) Christoph Lange
@ 2000-07-11 22:05   ` Vincent Lefevre
  2000-07-11 23:04     ` Bart Schaefer
  2000-07-12  8:26   ` Bart Schaefer
  1 sibling, 1 reply; 8+ messages in thread
From: Vincent Lefevre @ 2000-07-11 22:05 UTC (permalink / raw)
  To: zsh-users

On Tue, Jul 11, 2000 at 19:29:55 +0200, Christoph Lange wrote:
>   I found it annoying that the widget insert-last-word inserts `&' if the
> previous command was a background job. I'd rather like the last word
> *before* `&' to be inserted.

Me too!

> So I wrote a custom widget:
[snip]

IMHO, this behavior should be in zsh as standard.

-- 
Vincent Lefèvre <vincent@vinc17.org> - Web: <http://www.vinc17.org/> - 100%
validated HTML - Acorn Risc PC, Yellow Pig 17, Championnat International des
Jeux Mathématiques et Logiques, TETRHEX, etc.
Computer science / computer arithmetic / Arénaire project at LIP, ENS-Lyon


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-11 22:05   ` Vincent Lefevre
@ 2000-07-11 23:04     ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 2000-07-11 23:04 UTC (permalink / raw)
  To: zsh-users

On Jul 12, 12:05am, Vincent Lefevre wrote:
} Subject: Re: ZLE Widget: Insert last word (except &)
}
} On Tue, Jul 11, 2000 at 19:29:55 +0200, Christoph Lange wrote:
} >   I found it annoying that the widget insert-last-word inserts `&' if the
} > previous command was a background job. I'd rather like the last word
} > *before* `&' to be inserted.
} 
} Me too!

Presumably what you'd really rather is that the last non-separator word
is inserted.  Even with Christoph's widget, if you type "echo foo;" and
then invoke smart-insert-last-word you get ";" inserted.

} IMHO, this behavior should be in zsh as standard.

But there's more; "echo foo 2>&1" followed by {smart-,}insert-last-word
inserts "1", and prefixing it with ESC 2 inserts "2>&".

Or "(echo foo)", where the last word is ")".  What about "{ echo foo; }"
or the same suffixed with a redirection (inside or outside the braces)?

If we don't accept the shell syntax definition of a "word", how can we
choose a single definition of what constitutes a "word" that everyone
will agree on?

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-11 17:29 ` ZLE Widget: Insert last word (except &) Christoph Lange
  2000-07-11 22:05   ` Vincent Lefevre
@ 2000-07-12  8:26   ` Bart Schaefer
  2000-07-12 16:38     ` Christoph Lange
  1 sibling, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2000-07-12  8:26 UTC (permalink / raw)
  To: zsh-users

I wrote:
} If we don't accept the shell syntax definition of a "word", how can we
} choose a single definition of what constitutes a "word" that everyone
} will agree on?

The answer is, we don't, we use a style.  Which isn't (presently) ever done
with the builtin widgets, so you aren't going to see this as the default
behavior of insert-last-word any time soon.

---- 8< ---- cut ---- 8< ----
# smart-insert-last-word
# Inspired by Christoph Lange <langec@gmx.de> from zsh-users/3265.
#
# This function as a ZLE widget can replace insert-last-word, like so:
#
#   zle -N insert-last-word smart-insert-last-word
#
# With a numeric prefix, simply calls .insert-last-word, which is also the
# fall-through case in the event that "smart" word selection fails.
#
# Otherwise, the rightmost "interesting" word from the previous command is
# found and inserted.  The default definition of "interesting" is that the
# word contains at least one alphabetic character, slash, or backslash.
# This definition can be overridden by use of a style like so:
#
#   zstyle :insert-last-word match '*[[:alpha:]/\\]*'
#
# For example, you might want to include words that contain spaces:
#
#   zstyle :insert-last-word match '*[[:alpha:][:space:]/\\]*'
#
# Or include numbers as long as the word is at least two characters long:
#
#   zstyle :insert-last-word match '*([[:digit:]]?|[[:alpha:]/\\])*'
#
# That causes redirections like "2>" to be included.
#
# Note also that the style is looked up based on the widget name, so you
# can bind this function to different widgets to use different patterns:
#
#   zle -N insert-last-assignment smart-insert-last-word
#   zstyle :insert-last-assignment match '[[:alpha:]][][[:alnum:]]#=*'
#   bindkey '\e=' insert-last-assignment
#
# (The above is a contrived example since it works only if the previous
# command line included an assignment, but you get the idea.)

if [[ -z "$NUMERIC" ]]
then
    emulate -L zsh
    setopt extendedglob
    local lastcmd pattern
    integer cursor=$CURSOR        # Remember cursor position
    zle up-history || return 1    # Retrieve previous command
    lastcmd=( ${(z)BUFFER} )      # Split into shell words
    zle down-history              # Return to current command
    CURSOR=$cursor                # Restore cursor position
    integer i=$#lastcmd
    zstyle -s :$WIDGET match pattern ||
	pattern='*[[:alpha:]/\\]*'
    while ((i)); do
	if [[ $lastcmd[i] == $~pattern ]]; then
	    LBUFFER="$LBUFFER$lastcmd[i]"
	    return 0
	else
	    ((--i))
	fi
    done
fi
zle .insert-last-word
---- 8< ---- cut ---- 8< ----

Note that this presently doesn't work right when the previous command line
contains a [[ ... ]] expression that uses one of the (#x) forms of extended
pattern matching, e.g. (#i) to ignore case.  That's a bug in ${(z)...} (it
takes the # to be a comment introducer), so it should be fixed soon.  If
this really bothers you in the meantime, try adding

  local +h histchars=''

somewhere before the assignment to lastcmd -- but then it's broken for the
case of `setopt interactive_comments`, so choose your poison ...

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-12  8:26   ` Bart Schaefer
@ 2000-07-12 16:38     ` Christoph Lange
  2000-07-12 18:54       ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Christoph Lange @ 2000-07-12 16:38 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

> I wrote:
> } If we don't accept the shell syntax definition of a "word", how can we
> } choose a single definition of what constitutes a "word" that everyone
> } will agree on?
> 
> The answer is, we don't, we use a style.  Which isn't (presently) ever done
> with the builtin widgets, so you aren't going to see this as the default
> behavior of insert-last-word any time soon.
> 
> ---- 8< ---- cut ---- 8< ----
> # smart-insert-last-word
>
> [...]
>
> Note that this presently doesn't work right when the previous command line
> contains a [[ ... ]] expression that uses one of the (#x) forms of extended
> pattern matching, e.g. (#i) to ignore case.  That's a bug in ${(z)...} (it
> takes the # to be a comment introducer), so it should be fixed soon.  If
> this really bothers you in the meantime, try adding
> 
>   local +h histchars=''
> 
> somewhere before the assignment to lastcmd -- but then it's broken for the
> case of `setopt interactive_comments`, so choose your poison ...

There is another bug in your version of smart-insert-last-word: repeated
calls to it don't go back in the history. Rather than doing the word
splitting yourself, you should always call insert-last-word -- with an
argument of 2 or greater, when necessary.

The solution might be a synthesis of my first version and yours -- a widget
that is smarter than mine when determining the last word, but nevertheless
calls insert-last-word, so that the shell can go back the history on
subsequent calls.

Christoph

-- 
Descartes enters a pub. "Evening, Descartes. Same as usual?"
Descartes says: "No, I think not." -- and disappears.
Christoph Lange, langec@gmx.de, http://www.cul.de/home/yaph/, ICQ #51191833


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-12 16:38     ` Christoph Lange
@ 2000-07-12 18:54       ` Bart Schaefer
  2000-07-12 21:18         ` Christoph Lange
  0 siblings, 1 reply; 8+ messages in thread
From: Bart Schaefer @ 2000-07-12 18:54 UTC (permalink / raw)
  To: Christoph Lange; +Cc: zsh-users

On Jul 12,  6:38pm, Christoph Lange wrote:
} Subject: Re: ZLE Widget: Insert last word (except &)
}
} There is another bug in your version of smart-insert-last-word: repeated
} calls to it don't go back in the history.

Oops, I forgot about that behavior.

} Rather than doing the word
} splitting yourself, you should always call insert-last-word

Nah.

The fiddling with NUMERIC below serves two purposes:  One, it passes the
same value to both up-history and down-history without having to pass an
argument to each.  Two, `zle WIDGET -n NUM' is broken for NUM > 9.

---- 8< ---- cut ---- 8< ----
# smart-insert-last-word
# Inspired by Christoph Lange <langec@gmx.de> from zsh-users/3265;
# rewritten to correct multiple-call behavior after zsh-users/3270.
#
# This function as a ZLE widget can replace insert-last-word, like so:
#
#   zle -N insert-last-word smart-insert-last-word
#
# With a numeric prefix, behaves like insert-last-word, except that words
# in comments are ignored when interactive_comments is set.
#
# Otherwise, the rightmost "interesting" word from the previous command is
# found and inserted.  The default definition of "interesting" is that the
# word contains at least one alphabetic character, slash, or backslash.
# This definition can be overridden by use of a style like so:
#
#   zstyle :insert-last-word match '*[[:alpha:]/\\]*'
#
# For example, you might want to include words that contain spaces:
#
#   zstyle :insert-last-word match '*[[:alpha:][:space:]/\\]*'
#
# Or include numbers as long as the word is at least two characters long:
#
#   zstyle :insert-last-word match '*([[:digit:]]?|[[:alpha:]/\\])*'
#
# That causes redirections like "2>" to be included.
#
# Note also that the style is looked up based on the widget name, so you
# can bind this function to different widgets to use different patterns:
#
#   zle -N insert-last-assignment smart-insert-last-word
#   zstyle :insert-last-assignment match '[[:alpha:]][][[:alnum:]]#=*'
#   bindkey '\e=' insert-last-assignment

emulate -L zsh
setopt extendedglob

# Not strictly necessary:
# (($+_ilw_hist)) || integer -g _ilw_hist _ilw_count _ilw_cursor _ilw_lcursor

integer cursor=$CURSOR lcursor=$CURSOR
local lastcmd pattern numeric=$NUMERIC

# Save state for repeated calls
if (( HISTNO == _ilw_hist && cursor == _ilw_cursor )); then
    NUMERIC=$[_ilw_count+1]
    lcursor=$_ilw_lcursor
else
    NUMERIC=1
    _ilw_lcursor=$lcursor
fi
_ilw_hist=$HISTNO
_ilw_count=$NUMERIC

zle up-history || return 1    # Retrieve previous command
lastcmd=( ${(z)BUFFER} )      # Split into shell words
zle down-history              # Return to current command
CURSOR=$cursor                # Restore cursor position
NUMERIC=${numeric:-1}         # In case of fall through

(( NUMERIC > $#lastcmd )) && return 1

if [[ -z "$numeric" ]]
then
    integer i=1
    zstyle -s :$WIDGET match pattern ||
	pattern='*[[:alpha:]/\\]*'
    while ((i <= $#lastcmd)); do
	if [[ $lastcmd[-i] == $~pattern ]]; then
	    NUMERIC=$i
	    break
	else
	    ((--i))
	fi
    done
fi
LBUFFER[lcursor+1,cursor+1]=$lastcmd[-NUMERIC]
_ilw_cursor=$CURSOR
---- 8< ---- cut ---- 8< ----

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-12 18:54       ` Bart Schaefer
@ 2000-07-12 21:18         ` Christoph Lange
  2000-07-12 22:33           ` Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Christoph Lange @ 2000-07-12 21:18 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

On Wed, 12 Jul 2000, Bart Schaefer wrote:

> On Jul 12,  6:38pm, Christoph Lange wrote:
> } Subject: Re: ZLE Widget: Insert last word (except &)
> }
> } There is another bug in your version of smart-insert-last-word: repeated
> } calls to it don't go back in the history.
> 
> Oops, I forgot about that behavior.
> 
> } Rather than doing the word
> } splitting yourself, you should always call insert-last-word
> 
> Nah.
> 
> The fiddling with NUMERIC below serves two purposes:  One, it passes the
> same value to both up-history and down-history without having to pass an
> argument to each.  Two, `zle WIDGET -n NUM' is broken for NUM > 9.
> 
> ---- 8< ---- cut ---- 8< ----
> # smart-insert-last-word
>
> [...]

I didn't understand all of it, but now the functions even fails doing
elementar things:

% echo a &
a
% echo
  ^ [Alt+.] pressed

I found out another interesting thing about my first version. zsh goes up in
the history on subsequent calls of insert-last-word, but from the widget's
point of view, the position in the history remains the same. Either
determining the previous line with `fc -n -l -1' or -- like in your widget
-- going up the history and reading from $BUFFER always returns the previous
line relative from the position where the user started calling
insert-last-word. Just look at the following result:

% echo 1
% echo 1&
% [[Subsequent invocations of insert-last-word:]]
1. `1'
2. `echo'

lastcmd always contains `echo 1&', regardless of the shell going up the
history. Thus, the last but one word is inserted into the command line.

What to do?

Christoph

-- 
Q: After bootup, a linux machine hangs, showing the error
   message `login:'. How can I fix this?
A: This system hang is a big enough problem to justify
   replacing Linux with Windows 2000.
Christoph Lange, langec@gmx.de, http://www.cul.de/home/yaph/, ICQ #51191833



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ZLE Widget: Insert last word (except &)
  2000-07-12 21:18         ` Christoph Lange
@ 2000-07-12 22:33           ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 2000-07-12 22:33 UTC (permalink / raw)
  To: Christoph Lange; +Cc: zsh-users

On Wed, 12 Jul 2000, Christoph Lange wrote:

> I didn't understand all of it, but now the functions even fails doing
> elementar things:
> 
> % echo a &
> a
> % echo
>   ^ [Alt+.] pressed

Oops; I tried to edit a cut'n'paste screwup in place, and accidentally
re-inserted a line from the old version.  Change ((--i)) to ((++i)) in the
`else' inside the `while' loop.  Sorry about that.

> I found out another interesting thing about my first version. zsh goes up in
> the history on subsequent calls of insert-last-word, but from the widget's
> point of view, the position in the history remains the same. Either
> determining the previous line with `fc -n -l -1' or -- like in your widget
> -- going up the history and reading from $BUFFER always returns the previous
> line relative from the position where the user started calling
> insert-last-word.

That's why I had to the goofy bit with ((NUMERIC=_ilw_count+1)) in my
revised version.  That makes up-history go up the correct number of lines,
and down-history go back down the correct number.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2000-07-12 22:33 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20000711140506.5143gmx1@mx14.gmx.net>
2000-07-11 17:29 ` ZLE Widget: Insert last word (except &) Christoph Lange
2000-07-11 22:05   ` Vincent Lefevre
2000-07-11 23:04     ` Bart Schaefer
2000-07-12  8:26   ` Bart Schaefer
2000-07-12 16:38     ` Christoph Lange
2000-07-12 18:54       ` Bart Schaefer
2000-07-12 21:18         ` Christoph Lange
2000-07-12 22:33           ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).