zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: newuser system
@ 2005-11-23 11:13 Peter Stephenson
  2005-11-24  6:00 ` Bart Schaefer
  2005-11-29  1:58 ` Geoff Wing
  0 siblings, 2 replies; 14+ messages in thread
From: Peter Stephenson @ 2005-11-23 11:13 UTC (permalink / raw)
  To: Zsh hackers list

The main thing I've been wanting before making test builds for the first
4.3 release is a working zsh-newuser-install, otherwise it's not worth
distributing the zsh/newuser module.

Here's a first pass.  As this will be seen by a great many new users it
really needs to be tested as widely as possible.  I may well have done
lots of things that will confuse new users and which should therefore be
done some completely different way.  Consequently it would be very
helpful to have guinea pigs.

It's designed to be running assuming .zshrc doesn't initially exist and
doesn't assume (nor probe) any other shell settings.  You can run it
again with the argument -f to edit the settings it has added, but again
it assumes nothing else is trying to set the same things.

It's written to be relatively easy to extend (more so than compinstall,
with more generic functions).  This should be done with submenus: many
of the existing menus are already close to filling the screen and the
option setting menu is probably a bit too full.

Internationalization is another matter: the function as it stands is
useless for anyone who doesn't speak English, and I've warned about this
in the INSTALL file, but I haven't even begun to provide hooks for
translations.  Given that this is all shell code, I don't know whether
that would be easier with an existing system or with an ad-hoc text
database.

It uses compinstall to provide the completion set-up.  I've tweaked that
to make the functions co-operate better, but zsh-newuser-install needs
to run compinstall interactively to edit completion settings.  I've
fixed one bug in compinstall which was screwing up backslashes read in
from the previous configuration.

Index: INSTALL
===================================================================
RCS file: /cvsroot/zsh/zsh/INSTALL,v
retrieving revision 1.19
diff -u -r1.19 INSTALL
--- INSTALL	3 Oct 2005 09:00:44 -0000	1.19
+++ INSTALL	23 Nov 2005 10:56:32 -0000
@@ -231,6 +231,31 @@
 as make can become confused by build files created in the source directories.
 
 
+================================
+AUTOMATIC NEW USER CONFIGURATION
+================================
+
+In the default configuration, the shell comes with a system based around
+the zsh/newuser add-on module that detects when a user first starts the
+shell interactively and has no initialisation files (.zshenv, .zshrc,
+.zprofile or .zlogin).  The shell then executes code in the file
+scripts/newuser in the shared library area (by default
+/usr/local/share/zsh/<VERSION>/scripts/newuser).  This feature can be
+turned off simply by removing this script.  The module can be removed
+entirely from the configured shell by editing the line starting
+"name=zsh/newuser" int the config.modules file, which is generated in the
+top level distribution directory during configuration: change the line to
+include "link=no auto=no".
+
+The supplied script executes the function supplied as
+Functions/Newuser/zsh-newuser-install.  This function is currently under
+development.  It is probably preferable for administrators who wish to
+customize the system their own way to edit the newuser script in
+scripts/newuser.  Also, as there is currently no internationalization
+support, administrators of sites with users who mostly do not speak English
+may wish not to install the zsh/newuser module.
+
+
 =====================
 CONFIGURATION OPTIONS
 =====================
Index: NEWS
===================================================================
RCS file: /cvsroot/zsh/zsh/NEWS,v
retrieving revision 1.7
diff -u -r1.7 NEWS
--- NEWS	7 Nov 2005 10:56:34 -0000	1.7
+++ NEWS	23 Nov 2005 10:56:33 -0000
@@ -8,6 +8,10 @@
 - There is support for multibyte character sets in the line editor,
   though not the main shell.  See Multibyte Character Support in INSTALL.
 
+- The shell can now run an installation function for a new user
+  (one with no .zshrc, .zshenv, .zprofile or .zlogin file) without
+  any additional setting up by the administrator.
+
 - New option PROMPT_SP, on by default, to work around the problem that the
   line editor can overwrite output with no newline at the end.
 
Index: Completion/compinstall
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/compinstall,v
retrieving revision 1.8
diff -u -r1.8 compinstall
--- Completion/compinstall	20 Apr 2004 12:11:15 -0000	1.8
+++ Completion/compinstall	23 Nov 2005 10:56:36 -0000
@@ -1,3 +1,5 @@
+# Configure the completion system.
+
 emulate -L zsh
 setopt extendedglob
 
@@ -25,11 +27,25 @@
 
 typeset startline='# The following lines were added by compinstall'
 typeset endline='# End of lines added by compinstall'
-typeset ifile line fpath_line compinit_args
+typeset ifile line fpath_line compinit_args opt detect basic line2
 typeset -A styles
-typeset match mbegin mend warn_unknown warn_old warn_comment
+typeset match mbegin mend warn_unknown warn_old warn_comment output
 integer lines_found
 
+while getopts "do" opt; do
+  case $opt in
+    (d)
+    # Detect an existing compinstall setup.
+    detect=1
+    ;;
+
+    (o)
+    # Output basic setup information only.
+    basic=1
+    ;;
+  esac
+done
+
 #
 # Check the user's .zshrc, if any.
 #
@@ -60,6 +76,40 @@
   fi
 fi
 
+
+if [[ -n $detect ]]; then
+  __ci_tidyup
+  [[ $foundold = true ]]
+  return
+fi
+
+
+__ci_output() {
+  print -r "$startline"
+  [[ -n $output ]] && print -r "$output"
+  if [[ -n $ifile ]]; then
+    line="zstyle :compinstall filename ${(qq)ifile}"
+    print -r "$line"
+    eval "$line"
+  fi
+
+  [[ -n $fpath_line ]] && print -r "$fpath_line"
+
+  print -r "
+autoload -Uz compinit
+compinit${compinit_args:+ $compinit_args}"
+
+  print -r "$endline"
+}
+
+
+if [[ -n $basic ]]; then
+  __ci_output
+  __ci_tidyup
+  return
+fi
+
+
 local newifile=$ifile
 if [[ $foundold = true ]]; then
   print "I have found completion definitions in $ifile.
@@ -92,8 +142,19 @@
 
 if [[ $foundold = true ]]; then
   sed -n "/^[ 	]*$startline/,/^[ 	]*$endline/p" $ifile |
-  # Use the default read behaviour to handle any continuation lines.
-  while read line; do
+  # We can't use the default read behaviour to handle continuation lines
+  # since it messes up internal backslashes.
+  while read -r line; do
+    # detect real continuation backslashes by checking there are an
+    # odd number together.  i think this is reliable since the only
+    # other way of quoting a backslash involves following it with
+    # a closing quote.
+    while [[ $line = *\\ ]]; do
+      line2=${(M)line%%\\##}
+      (( ${#line2} & 1 )) || break
+      read -r line2 || break
+      line="${line[1,-2]}$line2"
+    done
     (( lines_found++ ))
     if [[ $line = *'$fpath'* ]]; then
       fpath_line=$line
@@ -119,7 +180,7 @@
     then
       compinit_args=$match[1]
     elif [[ $line != [[:blank:]]# &&
-      $line != [[:blank:]]#'autoload -Uz compinit' &&
+      $line != [[:blank:]]#'autoload '*' compinit' &&
       $line != [[:blank:]]#compinit &&
       $line != [[:blank:]]#zstyle[[:blank:]]#:compinstall* ]]; then
       warn_unknown="${warn_unknown:+$warn_unknown
@@ -379,7 +440,7 @@
 m.     Set options for _match: whether to assume a \`*' at the cursor.
 p.     Set options for _prefix: whether to add a space before the suffix.
 
-q.     Return to the without saving.
+q.     Return to the previous menu without saving.
 0.     Done setting completer options.
 "
 
@@ -1848,15 +1909,13 @@
 done
 
 
-local output
-
 if (( $#styles )); then
   typeset style stylevals context values
   for style in ${(ko)styles}; do
     stylevals=(${(f)styles[$style]})
     while (( $#stylevals )); do
       output="$output
-zstyle ${(qq)stylevals[1]} $style $stylevals[2]"
+zstyle ${(qq)stylevals[1]} $style ${stylevals[2]}"
       shift 2 stylevals
     done
   done
@@ -1875,22 +1934,7 @@
 # Assemble the complete set of lines to
 # insert.
 #
-{ print -r "$startline
-$output"
-  if [[ -n $ifile ]]; then
-    line="zstyle :compinstall filename ${(qq)ifile}"
-    print -r "$line"
-    eval "$line"
-  fi
-
-  [[ -n $fpath_line ]] && print -r "$fpath_line"
-
-  print -r "
-autoload -Uz compinit
-compinit${compinit_args:+ $compinit_args}"
-
-  print -r "$endline"
-} >$tmpout
+__ci_output >$tmpout
 
 if [[ -n $ifile ]]; then
   if [[ $ifile != *(zshrc|zlogin|zshenv) ]]; then 
Index: Functions/Newuser/zsh-newuser-install
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Newuser/zsh-newuser-install,v
retrieving revision 1.1
diff -u -r1.1 zsh-newuser-install
--- Functions/Newuser/zsh-newuser-install	26 Jul 2005 10:35:26 -0000	1.1
+++ Functions/Newuser/zsh-newuser-install	23 Nov 2005 10:56:39 -0000
@@ -1,23 +1,1005 @@
 # Function to install startup files for a new user.
-# This dummy version simply creates a new .zshrc with a comment.
-# FIXME: we don't want to distribute a file that does that, it
-# would be preferable to do nothing at all.
+# Currently it only creates or edits .zshrc.
+#
+# It can be run again by giving it the option "-f".
 
 # Sanitize environment.
 emulate -L zsh
+setopt extendedglob nonomatch warncreateglobal
 
+# How the function will be referred to.
+local myname=zsh-newuser-install
+# The directory in which to look for and save .zshrc.
 local zd=${ZDOTDIR:-$HOME}
+# The same directory in a user friendly form, i.e. with ~ replacement.
+# (We don't want to use glob_subst since that has other side effects.)
+local zdmsg
+# The message used if an other blank .zshrc is created.
+local msg="# Created by newuser for $ZSH_VERSION"
+# The lines marking the start and end of the section edited.
+local startline="# Lines configured by $myname"
+local endline="# End of lines configured by $myname"
+# Prompts used for reading a key.  The initial "?" is required.
+local shortprompt="?--- Type a key --- "
+local longprompt="?--- Type one of the keys in parentheses --- "
+# Prefix for all temporary files.  Any files starting with this
+# will be removed at the end of the script.
+local tmpfile=${TMPPREFIX:-/tmp/zsh}-zni-$$
+# Report of the state of settings for the top-level menu.
+local -A install_state
+# Values of all parameters etc. to be saved (including
+# those read in from the existing file.)
+local -A parsed_parameters parsed_options parsed_bindings parsed_keymaps
+# Corresponding state in a user-readable form.
+local -A state_parameters state_options state_bindings state_keymaps
+# Lines read in from between $startline and $endline which were
+# not understood.  These are retained but moved out of that section
+# with a message.
+local -a unparsed
+# Lines used in submenus: the setting to output in a form
+# that can be exeucuted (an assignment, setopt or unsetopt), a brief message
+# about the setting, and the state copied from and to state_parameters or
+# state_options.  Elements of all three arrays must correspond.
+local -a output_lines display_lines state_lines
+# Variable indicating some of the lines in the above variables
+# have been read in, i.e. the user has already configured the
+# particular set of settings.
+integer lines_read
+# Lines to set up completion.  This is special as it is only
+# edited by compinstall, not this function.
+local -a completion_lines
+# Utility variables
+local -a reply match mbegin mend
+# Key read from user, used all over the place.
+local key
+integer save lines_found
 
-# The zsh/newuser module already tests for the following, so this test only
-# triggers if zsh-newuser-install is run by hand.
-#
-# In future we may want to use this mechanism to update startup files.
-if [[ -e $zd/.zshenv || -e $zd/.zprofile || -e $zd/.zshrc || -e $zs/.zlogin ]]
-then
-  print "zsh-newuser-install:  startup files exist, aborting" >&2
+install_state[history]=Recommended
+install_state[completion]=Recommended
+
+# Don't save anything if interrupted.
+trap 'save=0' HUP INT QUIT
+
+# Substitute an initial ~ for human consumption.
+if [[ $zd = $HOME ]]; then
+  zdmsg="~"
+else
+  zdmsg=$zd
+fi
+
+# Don't run unless we can talk to the user.
+if [[ ! -t 0 || ! -t 1 ]]; then
+  if [[ $1 = -f ]]; then
+    print -r "$myname: can only be used interactively." >&2
+  fi
+  return 1
+fi
+
+# Don't run unless terminal is sane.
+if (( ${LINES:-0} < 15 || ${COLUMNS:-0} < 72 )); then
   return 1
 fi
 
-echo "# Created by newuser for $ZSH_VERSION" >$zd/.zshrc
+if [[ $1 != -f ]]; then
+  # The zsh/newuser module already tests for the following, so this test only
+  # triggers if zsh-newuser-install is run by hand.
+  if [[ -e $zd/.zshenv || -e $zd/.zprofile || \
+        -e $zd/.zshrc || -e $zd/.zlogin ]]; then
+    print -r "$myname:  startup files exist, aborting.
+
+Use the argument -f if you want to force the function to be run again." >&2
+    return 1
+  fi
+fi
+
+
+# start of try block for tidy-up in always block
+{
+
+########################################################################
+# Utility functions
+########################################################################
+
+# All internal functions start with __zni_.  These will be removed
+# when the main function exits.
+
+# Read existing lines from .zshrc, if any.
+__zni_retrieve_lines() {
+  local line
+
+  reply=()
+
+  lines_found=0
+
+  [[ -f $zd/.zshrc ]] || return 1
+
+  grep "$startline" $zd/.zshrc 1>/dev/null 2>&1 || return 1
+
+  lines_found=1
+
+  sed -n "/^[	]*$startline/,/^[	]*$endline/p" $zd/.zshrc |
+  while read -r line; do
+    reply+=($line)
+  done
+
+  return 0
+}
+
+
+# First argument is a state; other arguments are lines
+# to parse.  They should either contain single assignments or
+# setopt or unsetopt statements.  The state for each parameter
+# or option so parsed is set to the value given by the first argument.
+__zni_parse_lines() {
+  local line opt warned first
+  local -a args
+  local state=$1
+
+  shift
+
+  for line in "$@"; do
+    case $line in
+      ((#b)[[:blank:]]#([[:IDENT:]]##)=(*))
+      parsed_parameters[$match[1]]=$match[2]
+      state_parameters[$match[1]]=$state
+      ;;
+
+      ((#b)[[:blank:]]#(un|)setopt[[:blank:]]##(*))
+      # TBD: handle setopt noX / unsetopt X
+      for opt in ${=match[2]}; do
+	opt=${${opt//(#m)[[:upper:]]/${(L)MATCH}}//_}
+	if [[ $match[1] = un ]]; then
+	  parsed_options[$opt]=off
+	else
+	  parsed_options[$opt]=on
+	fi
+	state_options[$opt]=$state
+      done
+      ;;
+
+      ((#b)[[:blank:]]#bindkey[[:blank:]]##(*))
+      args=(${(z)match[1]})
+      # store keys unquoted: will need quoting for output.
+      first=${(Q)args[1]}
+      shift args
+      if [[ $first = -[ev] && ${#args} -eq 0 ]]; then
+	case $first in
+	  (-e)
+	  parsed_keymaps[main]=emacs
+	  ;;
+
+	  (-v)
+	  parsed_keymaps[main]=vi
+	  ;;
+	esac
+	state_keymaps[main]=$state
+      else
+	# TODO: handling keymap options
+	parsed_bindings[first]=${args[2,-1]}
+	state_bindings[first]=$state
+      fi
+      ;;
+
+      ([[:blank:]]#($startline|$endline|))
+      ;;
+
+      (*)
+      unparsed+=($line)
+      print -r "WARNING: failed to understand line:
+  $line
+which will be retained but not edited."
+      warned=1
+      ;;
+    esac
+  done
+
+  if [[ -n $warned ]]; then
+    read -k key$shortprompt
+  fi
+}
+
+# Apply defaults.  Arguments in the form
+#   -p parameter_name default_value description
+#      ...
+#   -o option_name default=on|off description
+#      ...
+#   -b bindkey_string default_value description
+#      ...
+#   -B default_keymap=emacs|vi|none description
+#
+# They're not really defaults (they're not the same as the
+# builtin defaults), so the description output is "not yet saved".
+#
+# All variables to be edited in this section must be mentioned,
+# though defaults can be blank in which case nothing will be
+# saved unless the variable is set by the user.  The description
+# is then "no value set".
+#
+# -B is a bit strange: it's simply designed to allow the user to
+# select "bindkey -e" for Emacs or "bindkey -v" for vi.  It only
+# takes a single argument.  Real key bindings use -b.
+#
+# This operation transfers some subset of settings from the parsed_*
+# and state_* variables to the *_lines variables for editing.
+__zni_apply_defaults() {
+  local un
+
+  # Reset the lines to be edited.
+  state_lines=()
+  display_lines=()
+  output_lines=()
+  lines_read=0
+
+  case $1 in
+    (-p)
+    shift
+    while [[ $# -gt 0 && $1 != -* ]]; do
+      # skip default if it was read in
+      if [[ -z $state_parameters[$1] ]]; then
+	parsed_parameters[$1]=$2
+	if [[ -n $2 ]]; then
+	  state_parameters[$1]="not yet saved"
+	else
+	  state_parameters[$1]="no value set"
+	fi
+      elif [[ $state_parameters[$1] = saved ]]; then
+	(( lines_read++ ))
+      fi
+      state_lines+=($state_parameters[$1])
+      display_lines+=("$3")
+      output_lines+=("$1=$parsed_parameters[$1]")
+
+      shift 3
+    done
+    ;;
+
+    (-o)
+    shift
+    while [[ $# -gt 0 && $1 != -* ]]; do
+      # skip default if there was a setting
+      if [[ -z $state_options[$1] ]]; then
+	parsed_options[$1]=$2
+	if [[ -n $2 ]]; then
+	  state_options[$1]="not yet saved"
+	else
+	  state_options[$1]="no value set"
+	fi
+      elif [[ $state_parameters[$1] = saved ]]; then
+	(( lines_read++ ))
+      fi
+      if [[ $parsed_options[$1] = on ]]; then
+	un=
+      else
+	# display as unsetopt even if no value to save yet
+	un=un
+      fi
+      state_lines+=($state_options[$1])
+      display_lines+=("$3")
+      output_lines+=("${un}setopt $1")
+
+      shift 3
+    done
+    ;;
+
+    (-b)
+    shift
+    # this will barf on bindings beginning -; there's no good
+    # reason to rebind that, even in vi command mode, so perhaps
+    # we just add it to the sanity checks when we get around to them.
+    while [[ $# -gt 0 && $1 != -* ]]; do
+      if [[ -z $state_bindings[$1] ]]; then
+	parsed_bindings[$1]=$2
+	if [[ -n $2 ]]; then
+	  state_bindings[$1]="not yet saved"
+	else
+	  state_bindings[$1]="no value set"
+	fi
+      elif [[ $state_bindings[$1] = saved ]]; then
+	(( lines_read++ ))
+      fi
+      state_lines+=($state_bindings[$1])
+      display_lines+=("$3")
+      output_lines+=("bindkey ${(qq)1}${2:+ $2}")
+
+      shift 3
+    done
+    ;;
+
+    (-B)
+    shift
+    if [[ -z $state_keymaps[main] ]]; then
+      parsed_keymaps[main] = $1
+      if [[ $1 = none ]]; then
+	state_keymaps[main]="no value set"
+      else
+	state_keymaps[main]="not yet saved"
+      fi
+    elif [[ $state_keymaps[main] = saved ]]; then
+      (( lines_read++ ))
+    fi
+    state_lines+=($state_keymaps[main])
+    display_lines+=("$2")
+    # display as -e even if no value to save yet
+    if [[ $parsed_keymaps[main] = vi ]]; then
+      output_lines+=("bindkey -v")
+    else
+      output_lines+=("bindkey -e")
+    fi
+
+    shift 2
+    ;;
+  esac
+}
+
+
+# Display and edit the settings given by the set of *_lines arrays.
+# If requested by the user, apply the settings, updating the
+# parsed_* and state_* variables.
+__zni_display_and_edit() {
+  integer i changes
+  local default edval ldisp rdisp
+  local -a states displays outputs tstval
+
+  states=("${state_lines[@]}")
+  displays=("${display_lines[@]}")
+  outputs=("${output_lines[@]}")
+
+  while true; do
+    clear
+    print -r $1
+    # snicker...
+    print -r ${(l.${#1}..=.):-}
+    print
+    if (( $# > 1 )); then
+      print -rl $argv[2,-1]
+      print
+    fi
+
+    # Output each setting with a description and state.
+    for (( i = 1; i <= ${#output_lines}; i++ )); do
+      default=$states[$i]
+      if [[ $default = ("no value set"|"not to be saved") ]]; then
+	ldisp="# $outputs[$i]"
+      else
+	ldisp=$outputs[$i]
+      fi
+      rdisp=${default:+($default)}
+      print -r "# ($i) $displays[$i]
+$ldisp${(l.$COLUMNS-${#ldisp}-${#rdisp}-1.):-}$rdisp"
+    done
+
+    if (( changes )); then
+      print -r "
+# (0)  Remember edits and return to main menu (does not save file yet)
+# (q)  Abandon edits and return to main menu
+"
+    else
+      print -r "
+# (0) or (q)  Return to main menu (no changes made yet)
+"
+    fi
+    read -k key$longprompt
+    print
+
+    if [[ $key = <-> && $key -ge 1 && $key -le ${#outputs} ]]; then
+      (( i = key ))
+      case $outputs[$i] in
+	((#b)(|un)setopt' '(*))
+	while true; do
+	  clear
+	  print "Option $match[2]:  $displays[$i]
+The option is currently ${match[1]:+un}set.
+Type:
+  (s) to set it
+  (u) to unset it
+  (n) not to set or unset it (use shell default)
+  (k) to keep the current setting:"
+	  read -k key$shortprompt
+	  print
+
+	  case $key in
+	    (s)
+	    (( changes++ ))
+	    outputs[$i]="setopt $match[2]"
+	    states[$i]="set but not saved"
+	    ;;
+
+	    (s)
+	    (( changes++ ))
+	    outputs[$i]="unsetopt $match[2]"
+	    states[$i]="set but not saved"
+	    ;;
+
+	    (n)
+	    (( changes++ ))
+	    outputs[$i]="unsetopt $match[2]"
+	    states[$i]="no value set"
+	    ;;
+
+	    (k)
+	    ;;
+
+	    (*)
+	    continue
+	    ;;
+	  esac
+	  break;
+	done
+	;;
+
+	((#b)([^=]##)=(*))
+	print -r "Variable ${match[1]}:  $displays[$i]
+Edit a value.  If it is left blank, nothing will be saved:"
+	edval=$match[2]
+	if vared -p "$match[1]> " -h edval; then
+	  # check this assignment doesn't produce multiple words
+	  # e.g. "HISTFILE=never rm -f ~" does produce multiple words...
+	  # this isn't perfect, e.g. "(this would get split on assignment)",
+	  # but that's fairly benign.
+	  tstval=(${=edval})
+	  if (( ${#tstval} > 1 )); then
+	    print "Error: value isn't a single word.
+Use quotes or backslashes if your value contains spaces.
+Note that you shouldn't quote an initial ~ in file names." >&2
+	    read -k key$shortprompt
+	    # now check the assignment works...
+	    # don't suppress any errors, they may be useful.
+	    # this means we need to suppress warncreateglobal.
+	  elif ! ( typeset -g $match[1]; eval "$match[1]=$edval" ); then
+	    print "Error: bad shell syntax in value.
+The value will be assigned to the variable exactly as you enter it.
+Make sure all quotes are paired." >&2
+	    read -k key$shortprompt
+	  else
+	    outputs[$i]="$match[1]=$edval"
+	    if [[ -n $edval ]]; then
+	      states[$i]="set but not saved"
+	    else
+	      states[$i]="no value set"
+	    fi
+	    (( changes++ ))
+	  fi
+	else
+	  read -k key'?--- Edit abandoned, type a key --- '
+	fi
+	;;
+
+	(bindkey' '-[ev])
+	while true; do
+	  print -nr "Pick a keymap (set of keys) to use when editing.
+Type:
+  (e) for Emacs keymap (recommended unless you are vi user)
+  (v) for Vi keymap
+  (n) not to set a keymap (allow shell to choose)
+  (k) to keep the current setting, "
+	  if [[ $state_lines[$i] = ("no value set"|"not to be saved") ]]
+	  then
+	    print -r "(n):"
+	  elif [[ $output_lines[$i] = *-v ]]; then
+	    print -r "(v):"
+	  else
+	    print -r "(e):"
+	  fi
+	  read -k key$longprompt
+	  case $key in
+	    (e)
+	    (( changes++ ))
+	    outputs[$i]="bindkey -e"
+	    states[$i]="set but not saved"
+	    ;;
+
+	    (v)
+	    (( changes++ ))
+	    outputs[$i]="bindkey -v"
+	    states[$i]="set but not saved"
+	    ;;
+
+	    (n)
+	    (( changes++ ))
+	    outputs[$i]="bindkey -e"
+	    states[$i]="not to be saved"
+	    ;;
+
+	    (k)
+	    ;;
+
+	    (*)
+	    continue
+	    ;;
+	  esac
+	  break
+	done
+	;;
+
+	(bindkey' '*)
+	# TODO: this needs writing.  We need to be able to read
+	# keys and translate them, sanity check them, and ideally
+	# handle keymaps, at least vi command and insert.
+	;;
+
+	(*)
+	print "*** Internal error: bad setting '$outputs[$i]' ***" >&2
+	read -k key'?--- Type a key in forlorn hope --- '
+	;;
+      esac
+    elif [[ $key = 0 ]]; then
+      # Update the *_lines variables
+      state_lines=("${states[@]}")
+      display_lines=("${displays[@]}")
+      output_lines=("${outputs[@]}")
+
+      # Also save any lines suitably marked to parsed_* and state_*
+      # by rerunning __zni_parse_lines on each such line.
+      for (( i = 1; i <= ${#output_lines}; i++ )); do
+	if [[ $state_lines[$i] = ("set but not saved"|"not to be saved") ]]
+	then
+	  __zni_parse_lines $state_lines[$i] $output_lines[$i]
+	fi
+      done
+
+      return $(( changes == 0 ))
+    elif [[ $key = [qQ] ]]; then
+      return 1
+    fi
+  done
+}
+
+
+# Print and despatch a submenu.
+# The first argument is the title.  The remaining arguments
+# are pairs of descriptions and functions to execute.
+# There shouldn't be more than 9 entries.
+# The usual entries 0 and q are added automatically.
+__zni_submenu() {
+  local title=$1
+  local desc func
+  local -a descs funcs
+  integer i
+
+  shift
+
+  clear
+  print -r $title
+  print -r ${(l.${#title}..=.):-}
+
+  for desc func; do
+    if [[ -z $func ]]; then
+      print "*** Internal error: bad argument set for __zni_submenu ***" >&2
+      read -k key'?--- Type a key in forlorn hope --- '
+      return 1
+    fi
+
+    descs+=($desc)
+    funcs+=($func)
+  done
+
+  while true; do
+    for (( i = 1; i <= ${#descs}; i++ )); do
+      print -r "
+($i)  $descs[$i]"
+    done
+    print -r "
+(0) or (q)  Return to previous menu"
+
+    read -k key$longprompt
+
+    if [[ $key = [0qQ] ]]; then
+      return 1
+    elif (( key >= 1 && key <= ${#funcs} )); then
+      $funcs[$key]
+    fi
+  done
+}
+
+
+# Save all values that have been edited to .zshrc.
+__zni_save() {
+  local key optline newline
+  local -a on_opts off_opts lines lines2
+  integer i
+
+  # Record lines containing parameter settings, sorted.
+  for key in ${(ok)parsed_parameters}; do
+    if [[ $state_parameters[$key] != ("no value set"|"not to be saved") ]]
+    then
+      lines+=("$key=$parsed_parameters[$key]")
+    fi
+  done
+
+  # Search through sorted options, make list of those to
+  # be turned on and off.  Those marked "no value set" aren't
+  # to be output.
+  for key in ${(ok)parsed_options}; do
+    if [[ $state_options[$key] != ("no value set"|"not to be saved") ]]; then
+      if [[ $parsed_options[$key] = on ]]; then
+	on_opts+=($key)
+      else
+	off_opts+=($key)
+      fi
+    fi
+  done
+
+  # Construct lines of options to turn on, keeping them short.
+  optline="setopt"
+  for (( i = 1; i <= ${#on_opts}; i++ )); do
+    newline="$optline $on_opts[$i]"
+    if [[ ${#newline} -ge 72 ]]; then
+      lines+=($optline)
+      optline="setopt $on_opts[$i]"
+    else
+      optline=$newline
+    fi
+    if (( i == ${#on_opts} )); then
+      lines+=($optline)
+    fi
+  done
+
+  # Construct lines of options to turn off, keeping them short.
+  optline="unsetopt "
+  for (( i = 1; i <= ${#off_opts}; i++ )); do
+    newline="$optline $off_opts[$i]"
+    if [[ ${#newline} -ge 72 ]]; then
+      lines+=($optline)
+      optline="unsetopt $off_opts[$i]"
+    else
+      optline=$newline
+    fi
+    if (( i == ${#off_opts} )); then
+      lines+=($optline)
+    fi
+  done
+
+  # Construct lines of bindkey commands.  First the keymap.
+  if [[ $state_keymaps[main] != (|"no value set"|"not to be saved") ]]; then
+    case $parsed_keymaps[main] in
+      (emacs)
+      lines+=("bindkey -e")
+      ;;
+
+      (vi)
+      lines+=("bindkey -v")
+      ;;
+    esac
+  fi
+  # Now bindings.
+  for key in ${(ok)parsed_bindings}; do
+    if [[ $state_bindings[$key] != ("no value set"|"not to be saved") ]]; then
+      lines+=("bindkey ${(qq)key} ${parsed_bindings[$key]}")
+    fi
+  done
+
+  # Save the lines with a start and end marker to a temporary file.
+  print -rl $startline $lines $endline >$tmpfile
+
+  if (( ${#unparsed} )); then
+    print "# The following lines were read by $myname.
+# They were moved here as they could not be understood.
+# $(date)
+${(F)unparsed}
+# End of lines moved by $myname." >>$tmpfile
+  fi
+
+  if grep "$startline"  $zd/.zshrc 1>/dev/null 2>&1; then
+    # Found the start line; replace the section.
+    # We could this by reading the lines in zsh, but in case
+    # the .zshrc is huge it's perhaps better to use sed.
+    sed -e "/^[		]*$endline/r $tmpfile
+/^[	]*$startline/,/^[	]*$endline/d" $zd/.zshrc >${tmpfile}.repl &&
+    cp ${tmpfile}.repl $zd/.zshrc
+  else
+    # No current start marker; just append.
+    cat $tmpfile >>$zd/.zshrc
+  fi
+}
+
+
+########################################################################
+# Specific configurations
+########################################################################
+
+__zni_history_config() {
+  __zni_apply_defaults -p \
+    HISTORY 1000 "Number of lines of history kept within shell" \
+    HISTFILE $zdmsg/.histfile "File where history is saved" \
+    SAVEHIST 1000 "Number of lines of history to save to \$HISTFILE"
+
+  if __zni_display_and_edit "History configuration"; then
+    install_state[history]="Unsaved changes"
+    save=1
+  fi
+}
+
+
+__zni_completion_config() {
+  autoload -Uz compinstall
+  if compinstall -d; then
+    print "The completion system has already been activated.
+You can run the configuration tool (compinstall) at any time by typing
+   autoload -Uz compinstall
+   compinstall
+Do you wish to run it now [y/n]?"
+    read -k key$shortprompt
+    if [[ $key = [yY] ]]; then
+      compinstall
+    fi
+    print
+  else
+    while true; do
+      clear
+      print "The new completion system (compsys) allows you to complete
+commands, arguments and special shell syntax such as variables.  It provides
+completions for a wide range of commonly used commands in most cases simply
+by typing the TAB key.  Documentation is in the zshcompsys manual page.
+If it is not turned on, only a few simple completions such as filenames
+are available but the time to start the shell is slightly shorter.
+
+You can:
+  (1)  Turn on completion with the default options.
+
+  (2)  Run the configuration tool (compinstall).  You can also run
+       this from the command line with the following commands:
+        autoload -Uz compinstall
+        compinstall
+       if you don't want to configure completion now.
+
+  (0)  Don't turn on completion.
+"
+      read -k key$longprompt
+      case $key in
+	(1)
+	completion_lines=${(f)"$(compinstall -o)"}
+	install_state[completion]="Unsaved changes"
+	save=1
+	;;
+
+	(2)
+	compinstall
+	install_state[completion]="Configured"
+	;;
+
+	(0)
+	completion_lines=()
+	install_state[completion]="Recommended"
+	;;
+
+	(*)
+	continue
+	;;
+      esac
+      break
+    done
+  fi
+}
+
+__zni_bindkey_config() {
+  __zni_apply_defaults -B none "Change default editing configuration"
+
+  if __zni_display_and_edit "Default editing configuration" \
+    "The keys in the shell's line editor can be made to behave either" \
+    "like Emacs or like Vi, two common Unix editors.  If you have no" \
+    "experience of either, Emacs is recommended.  If you don't pick one," \
+    "the shell will try to guess based on the EDITOR environment variable." \
+    "Usually it's better to pick one explicitly."; then
+    install_state[bindkey]="Unsaved changes"
+    save=1
+  fi
+}
+
+__zni_completion_save() {
+  if (( ${#completion_lines} )); then
+    # We don't try to replace existing lines of completion configuration ---
+    # that's up to compinstall.  We should already have tested that
+    # there was no existing completion set up.
+    print -rl $completion_lines >>$zd/.zshrc
+  fi
+}
+
+
+__zni_options_config() {
+  # when we have enough, should use:
+  #   __zni_submenu "Common shell options"
+
+  # This is deliberately just a tiny selection.
+  # Feel free to extend it, but if you do, consider using __zni_submenu.
+  # The "no" prefix is used to indicate options on by default.
+  __zni_apply_defaults -o autocd '' "Change directory given just path" \
+    extendedglob '' "Use additional pattern matching features" \
+    appendhistory '' "Append new history lines instead of overwriting" \
+    nonomatch '' "Pass unmatched patterns to command instead of error" \
+    nobeep '' "Don't beep on errors" \
+    notify '' "Immediately report changes in background job status"
+
+  if __zni_display_and_edit "Common shell options" \
+  "The following are some of the shell options that are most often used." \
+  "The descriptions are very brief; if you would like more information," \
+  "read the zshoptions manual page (type \"man zshoptions\")."; then
+    install_state[options]="Unsaved changes"
+    save=1
+  fi
+}
+
+
+########################################################################
+# Main function
+########################################################################
+
+# Read and parse any existing lines, in case the function
+# was called again.
+__zni_retrieve_lines &&
+  __zni_parse_lines saved "$reply[@]"
+
+if [[ $state_parameters[HISTORY] = saved ]]; then
+  install_state[history]="Saved"
+fi
+autoload -Uz compinstall
+zstyle :compinstall filename $zd/.zshrc
+if compinstall -d; then
+  install_state[completion]="Saved"
+fi
+
+
+clear
+print -r "This is the Z Shell configuration function for new users, $myname."
+if [[ $1 != -f ]]; then
+  print -r "You are seeing this message because you have no zsh startup files
+(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory
+$zdmsg).  This function can help you with a few settings that should
+make your use of the shell easier."
+fi
+
+print -r "
+You can:
+
+(q)  Quit and do nothing.  The function will be run again next time."
+if [[ ! -f $zd/.zshrc ]]; then
+  print -r "
+(0)  Exit, creating the file $zdmsg/.zshrc containing just a comment.
+     That will prevent this function being run again."
+fi
+print -r "
+(1)  Continue to main menu.
+"
+
+read -k key$longprompt
+print
+
+case $key in
+  ([qQ])
+  return 0
+  ;;
+
+  (0)
+  print -r $msg >$zd/.zshrc
+  return 0
+  ;;
+
+  (1)
+  ;;
+
+  (*)
+  print -r "Aborting."
+  if [[ $1 != -f ]]; then
+    print "The function will be run again next time.  To prevent this, execute:
+  touch $zdmsg/.zshrc"
+  fi
+  return 1
+  ;;
+esac
+
+while true; do
+  clear
+  print -nr "Please pick one of the following options:
+
+(1)  Configure settings for history, i.e. command lines remembered
+     and saved by the shell.\
+${install_state[history]:+  ($install_state[history].)}
+
+(2)  "
+  if [[ $install_state[completion] = Recommended ]]; then
+    print -nr "Configure"
+  else
+    print -nr "Use"
+  fi
+  print -r " the new completion system.\
+${install_state[completion]:+  ($install_state[completion].)}
+
+(3)  Configure how keys behave when editing command lines.
+
+(4)  Pick some of the more common shell options.  These are simple on
+     or off switches controlling the shell's features.  \
+${install_state[options]:+  ($install_state[options].)}
+"
+  print -nr "(0)  Exit, "
+  if (( save )); then
+    print -r "saving the new settings.  They will take effect immediately."
+  elif [[ -f $zd/.zshrc ]]; then
+    print -r "leaving the existing $zdmsg/.zshrc alone."
+  else
+    print -r "creating a blank $zdmsg/.zshrc file."
+  fi
+  print -r "
+(a)  Abort all settings and start from scratch.  Note this will overwrite
+     any settings from $myname already in the startup file.
+     It will not alter any of your other settings, however."
+  if [[ $1 = -f ]]; then
+    print -r "
+(q)  Quit and do nothing else."
+  else
+    print -r "
+(q)  Quit and do nothing else.  The function will be run again next time."
+  fi
+
+  read -k key$longprompt
+  print
+
+  case $key in
+    ([qQ])
+    break
+    ;;
+
+    ([aA])
+    parsed_parameters=()
+    state_parameters=()
+    parsed_options=()
+    state_options=()
+    parsed_keymaps=()
+    state_keymaps=()
+    parsed_bindings=()
+    state_bindings=()
+    unparsed=()
+    ;;
+
+    (0)
+    clear
+    if (( save )); then
+      if [[ -f $zd/.zshrc ]]; then
+	cp $zd/.zshrc $zd/.zshrc.zni &&
+	print -r "Copied old '$zdd/.zshrc' to '$zdd/.zshrc.zni'.
+"
+      fi
+
+      __zni_save
+      __zni_completion_save
+    elif [[ ! -f $zd/.zshrc ]]; then
+      print -r $msg >$zd/.zshrc
+    fi
+    if [[ $1 != -f ]]; then
+      print -r "The function will not be run in future, but you can run
+it yourself as follows:
+  autoload $myname
+  $myname -f
+
+The code added to $zdmsg/.zshrc is marked by the lines
+$startline
+$endline
+You should not edit anything between these lines if you intend to
+run $myname again.  You may, however, edit any other part
+of the file."
+    fi
+    break
+    ;;
+
+    (1)
+    __zni_history_config
+    ;;
+
+    (2)
+    __zni_completion_config
+    ;;
+
+    (3)
+    __zni_bindkey_config
+    ;;
+
+    (4)
+    __zni_options_config
+    ;;
+  esac
+done
 
-unfunction zsh-newuser-install
+} always {
+  # Tidy up: always executed unless the shell is stopped dead
+  # in its tracks.
+  unfunction -m $myname __zni_\*
+  rm -f $tmpfile*
+}

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


This message has been scanned for viruses by BlackSpider MailControl - www.blackspider.com


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

* Re: PATCH: newuser system
  2005-11-23 11:13 PATCH: newuser system Peter Stephenson
@ 2005-11-24  6:00 ` Bart Schaefer
  2005-11-24  6:17   ` Clint Adams
                     ` (2 more replies)
  2005-11-29  1:58 ` Geoff Wing
  1 sibling, 3 replies; 14+ messages in thread
From: Bart Schaefer @ 2005-11-24  6:00 UTC (permalink / raw)
  To: Zsh hackers list

On Nov 23, 11:13am, Peter Stephenson wrote:
}
} Here's a first pass.

This is an impressive piece of work.

} As this will be seen by a great many new users it
} really needs to be tested as widely as possible.

Am I wrong in thinking this could be tested by starting the shell with
ZDOTDIR in the environment pointing to an empty directory?

} It's designed to be running assuming .zshrc doesn't initially exist and
} doesn't assume (nor probe) any other shell settings.

Presuming that Clint will do something sensible for Debian, we should find
people to check a few other standard OS distributions (FreeBSD, NetBSD,
RedHat Linux, perhaps Solaris, etc.) to see if their standard new-user
skeletons might already include a .zshrc.  I don't recall having seen any
but I'm not exposed to as many OS variants as I used to be.

Misc. stuff:

} Index: INSTALL
} +"name=zsh/newuser" int the config.modules file, which is generated in the
                       ^^
(I didn't proofread the rest so closely, I fear.)

} +# Substitute an initial ~ for human consumption.
} +if [[ $zd = $HOME ]]; then
} +  zdmsg="~"
} +else
} +  zdmsg=$zd
} +fi

  zdmsg=${(%):-%~}

(How's *that* for obfuscation?)

Regarding keymaps ... it might be helpful if the explanatory text were
to recommend choosing the emacs keymap, as that's the one assumed by
most of the completion system initialization and the one most similar
to other line editors (e.g. bash/readline).


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

* Re: PATCH: newuser system
  2005-11-24  6:00 ` Bart Schaefer
@ 2005-11-24  6:17   ` Clint Adams
  2005-11-24  6:28   ` Danek Duvall
  2005-11-24 11:42   ` Peter Stephenson
  2 siblings, 0 replies; 14+ messages in thread
From: Clint Adams @ 2005-11-24  6:17 UTC (permalink / raw)
  To: Zsh hackers list

> Presuming that Clint will do something sensible for Debian, we should find

I plan to drop /etc/skel/.zshrc as soon as the newuser stuff finds its
way into a release tarball.


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

* Re: PATCH: newuser system
  2005-11-24  6:00 ` Bart Schaefer
  2005-11-24  6:17   ` Clint Adams
@ 2005-11-24  6:28   ` Danek Duvall
  2005-11-24 11:42   ` Peter Stephenson
  2 siblings, 0 replies; 14+ messages in thread
From: Danek Duvall @ 2005-11-24  6:28 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

On Thu, Nov 24, 2005 at 06:00:54AM +0000, Bart Schaefer wrote:

> } It's designed to be running assuming .zshrc doesn't initially exist and
> } doesn't assume (nor probe) any other shell settings.
> 
> Presuming that Clint will do something sensible for Debian, we should find
> people to check a few other standard OS distributions (FreeBSD, NetBSD,
> RedHat Linux, perhaps Solaris, etc.) to see if their standard new-user
> skeletons might already include a .zshrc.  I don't recall having seen any
> but I'm not exposed to as many OS variants as I used to be.

Solaris does not (nor will it, likely), though obviously any individual
administrator may have set such a thing up.  Zsh might include
documentation saying that if there is a skeleton .zshrc, you might include
certain lines in it to provide the same behavior as the zsh default ...

danek


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

* Re: PATCH: newuser system
  2005-11-24  6:00 ` Bart Schaefer
  2005-11-24  6:17   ` Clint Adams
  2005-11-24  6:28   ` Danek Duvall
@ 2005-11-24 11:42   ` Peter Stephenson
  2005-11-24 18:20     ` Bart Schaefer
  2005-11-24 18:52     ` Wayne Davison
  2 siblings, 2 replies; 14+ messages in thread
From: Peter Stephenson @ 2005-11-24 11:42 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer <schaefer@brasslantern.com> wrote:
> This is an impressive piece of work.

Thank you.

> } As this will be seen by a great many new users it
> } really needs to be tested as widely as possible.
> 
> Am I wrong in thinking this could be tested by starting the shell with
> ZDOTDIR in the environment pointing to an empty directory?

That works fine.  Anyone can try it out by:

mkdir /tmp/zdotdir
autoload -Uz zsh-newuser-install
ZDOTDIR=/tmp/zdotdir zsh-newuser-install

(add -f to the end if there's already a .zshrc there.)

> } Index: INSTALL
> } +"name=zsh/newuser" int the config.modules file, which is generated in the
>                        ^^
> (I didn't proofread the rest so closely, I fear.)

I'll check that in.

> } +# Substitute an initial ~ for human consumption.
> } +if [[ $zd = $HOME ]]; then
> } +  zdmsg="~"
> } +else
> } +  zdmsg=$zd
> } +fi
> 
>   zdmsg=${(%):-%~}
> 
> (How's *that* for obfuscation?)

That would deserve another "snicker", but $zd isn't necessarily the current
directory at that point, and we'd like to keep the directory after the
function exits... still, it's certainly a good idea to fix directories
under $HOME and I've done that in the patch.

> Regarding keymaps ... it might be helpful if the explanatory text were
> to recommend choosing the emacs keymap, as that's the one assumed by
> most of the completion system initialization and the one most similar
> to other line editors (e.g. bash/readline).

This is the message you get when you enter the appropriate menu, so it's
explained... but maybe I could set the initial state to "Recommended" and
the default so that it picks "bindkey -e" unless you explicitly tell it not
to?  (This is what happens in the history menu---if you pick that option it
sets your HISTSIZE and SAVEHIST to 1000 unless you explicitly edit them.)


Default editing configuration
=============================

The keys in the shell's line editor can be made to behave either
like Emacs or like Vi, two common Unix editors.  If you have no
experience of either, Emacs is recommended.  If you don't pick one,
the shell will try to guess based on the EDITOR environment variable.
Usually it's better to pick one explicitly.

# (1) Change default editing configuration
# bindkey -e                                                     (no value set)

# (0) or (q)  Return to main menu (no changes made yet)

--- Type one of the keys in parentheses ---


Index: INSTALL
===================================================================
RCS file: /cvsroot/zsh/zsh/INSTALL,v
retrieving revision 1.20
diff -u -r1.20 INSTALL
--- INSTALL	23 Nov 2005 11:29:20 -0000	1.20
+++ INSTALL	24 Nov 2005 11:40:59 -0000
@@ -243,7 +243,7 @@
 /usr/local/share/zsh/<VERSION>/scripts/newuser).  This feature can be
 turned off simply by removing this script.  The module can be removed
 entirely from the configured shell by editing the line starting
-"name=zsh/newuser" int the config.modules file, which is generated in the
+"name=zsh/newuser" in the config.modules file, which is generated in the
 top level distribution directory during configuration: change the line to
 include "link=no auto=no".
 
Index: Functions/Newuser/zsh-newuser-install
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Newuser/zsh-newuser-install,v
retrieving revision 1.2
diff -u -r1.2 zsh-newuser-install
--- Functions/Newuser/zsh-newuser-install	23 Nov 2005 11:29:21 -0000	1.2
+++ Functions/Newuser/zsh-newuser-install	24 Nov 2005 11:41:00 -0000
@@ -61,8 +61,8 @@
 trap 'save=0' HUP INT QUIT
 
 # Substitute an initial ~ for human consumption.
-if [[ $zd = $HOME ]]; then
-  zdmsg="~"
+if [[ $zd = $HOME(#b)(|/*) ]]; then
+  zdmsg="~$match[1]"
 else
   zdmsg=$zd
 fi

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


This message has been scanned for viruses by BlackSpider MailControl - www.blackspider.com


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

* Re: PATCH: newuser system
  2005-11-24 11:42   ` Peter Stephenson
@ 2005-11-24 18:20     ` Bart Schaefer
  2005-11-25 10:24       ` Peter Stephenson
  2005-11-24 18:52     ` Wayne Davison
  1 sibling, 1 reply; 14+ messages in thread
From: Bart Schaefer @ 2005-11-24 18:20 UTC (permalink / raw)
  To: zsh-workers

On Nov 24, 11:42am, Peter Stephenson wrote:
}
} >   zdmsg=${(%):-%~}
} > 
} > (How's *that* for obfuscation?)
} 
} That would deserve another "snicker", but $zd isn't necessarily the current
} directory at that point

Sorry, my obfuscation was incomplete. :-)

      PWD=$zd eval 'zdmsg=${(%):-%~}'

} [...] maybe I could set the initial [keymap] state to "Recommended"
} and the default so that it picks "bindkey -e" unless you explicitly
} tell it not to?

Sounds like the right idea.


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

* Re: PATCH: newuser system
  2005-11-24 11:42   ` Peter Stephenson
  2005-11-24 18:20     ` Bart Schaefer
@ 2005-11-24 18:52     ` Wayne Davison
  1 sibling, 0 replies; 14+ messages in thread
From: Wayne Davison @ 2005-11-24 18:52 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

I gave the latest code a try, and I noticed one minor problem.  While
configuring the completion system, I first chose option "1" (to use the
defaults).  Then I decided to go back into the same menu and choose
option "2" instead (to run compinstall).  At the end, I had two
compinstall sections, one at the top of the .zshrc, and one at the
bottom.  This problem doesn't occur if I only choose one of the two
options.

..wayne..


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

* Re: PATCH: newuser system
  2005-11-24 18:20     ` Bart Schaefer
@ 2005-11-25 10:24       ` Peter Stephenson
  2005-11-26 23:18         ` Bart Schaefer
  0 siblings, 1 reply; 14+ messages in thread
From: Peter Stephenson @ 2005-11-25 10:24 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer <schaefer@brasslantern.com> wrote:
> Sorry, my obfuscation was incomplete. :-)
> 
>       PWD=$zd eval 'zdmsg=${(%):-%~}'

I don't think that works... I think it's because the internal variable
doesn't get set when you change PWD, rather PWD is set as a normal variable
when you change directory.

Trying this showed up another problem which I'll patch separately.

> } [...] maybe I could set the initial [keymap] state to "Recommended"
> } and the default so that it picks "bindkey -e" unless you explicitly
> } tell it not to?
> 
> Sounds like the right idea.

This changes that, and also fixes the fact that actually if you didn't edit
the recommended settings then they weren't saved.  It also fixes the
problem noticed by Wayne: if compinstall has been run and returned status
0, I assume there's nothing more to do.  There are a few minor fixes,
including skipping the initial explanatory screen if the user explicitly
ran the function with the -f argument.

Index: Functions/Newuser/zsh-newuser-install
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/Newuser/zsh-newuser-install,v
retrieving revision 1.3
diff -u -r1.3 zsh-newuser-install
--- Functions/Newuser/zsh-newuser-install	24 Nov 2005 11:46:47 -0000	1.3
+++ Functions/Newuser/zsh-newuser-install	25 Nov 2005 10:15:16 -0000
@@ -56,6 +56,7 @@
 
 install_state[history]=Recommended
 install_state[completion]=Recommended
+install_state[bindkey]=Recommended
 
 # Don't save anything if interrupted.
 trap 'save=0' HUP INT QUIT
@@ -344,6 +345,11 @@
   displays=("${display_lines[@]}")
   outputs=("${output_lines[@]}")
 
+  if [[ -n ${states[(r)not yet saved]} ]]; then
+    # default should be installed, unless user says otherwise
+    (( changes++ ))
+  fi
+
   while true; do
     clear
     print -r $1
@@ -531,7 +537,8 @@
       # Also save any lines suitably marked to parsed_* and state_*
       # by rerunning __zni_parse_lines on each such line.
       for (( i = 1; i <= ${#output_lines}; i++ )); do
-	if [[ $state_lines[$i] = ("set but not saved"|"not to be saved") ]]
+	if [[ $state_lines[$i] = \
+	  ("set but not saved"|"not to be saved"|"not yet saved") ]]
 	then
 	  __zni_parse_lines $state_lines[$i] $output_lines[$i]
 	fi
@@ -659,6 +666,15 @@
       (vi)
       lines+=("bindkey -v")
       ;;
+
+      (none)
+      ;;
+
+      (*)
+      print -r "\
+*** Internal error: bad type $parsed_keymaps[main] for keymap ***" >&2
+      read -k key'?--- Type a key in forlorn hope --- '
+      ;;
     esac
   fi
   # Now bindings.
@@ -753,8 +769,12 @@
 	;;
 
 	(2)
-	compinstall
-	install_state[completion]="Configured"
+	if compinstall; then
+	  install_state[completion]="Configured"
+	  # compinstall has done it's thing, so we don't need
+	  # to write anything.
+	  completion_lines=()
+	fi
 	;;
 
 	(0)
@@ -772,7 +792,7 @@
 }
 
 __zni_bindkey_config() {
-  __zni_apply_defaults -B none "Change default editing configuration"
+  __zni_apply_defaults -B emacs "Change default editing configuration"
 
   if __zni_display_and_edit "Default editing configuration" \
     "The keys in the shell's line editor can be made to behave either" \
@@ -838,53 +858,54 @@
 fi
 
 
-clear
-print -r "This is the Z Shell configuration function for new users, $myname."
+# skip initial screen if the function was deliberately run by the user.
 if [[ $1 != -f ]]; then
-  print -r "You are seeing this message because you have no zsh startup files
+  clear
+  print -r "This is the Z Shell configuration function for new users, $myname.
+You are seeing this message because you have no zsh startup files
 (the files .zshenv, .zprofile, .zshrc, .zlogin in the directory
 $zdmsg).  This function can help you with a few settings that should
-make your use of the shell easier."
-fi
+make your use of the shell easier.
 
-print -r "
 You can:
 
 (q)  Quit and do nothing.  The function will be run again next time."
-if [[ ! -f $zd/.zshrc ]]; then
-  print -r "
+  if [[ ! -f $zd/.zshrc ]]; then
+    print -r "
 (0)  Exit, creating the file $zdmsg/.zshrc containing just a comment.
      That will prevent this function being run again."
-fi
-print -r "
+  fi
+  print -r "
 (1)  Continue to main menu.
 "
 
-read -k key$longprompt
-print
+  read -k key$longprompt
+  print
 
-case $key in
-  ([qQ])
-  return 0
-  ;;
+  case $key in
+    ([qQ])
+    return 0
+    ;;
 
-  (0)
-  print -r $msg >$zd/.zshrc
-  return 0
-  ;;
+    (0)
+    print -r $msg >$zd/.zshrc
+    return 0
+    ;;
 
-  (1)
-  ;;
+    (1)
+    ;;
 
-  (*)
-  print -r "Aborting."
-  if [[ $1 != -f ]]; then
-    print "The function will be run again next time.  To prevent this, execute:
+    (*)
+    print -r "Aborting."
+    if [[ $1 != -f ]]; then
+      print "\
+The function will be run again next time.  To prevent this, execute:
   touch $zdmsg/.zshrc"
-  fi
-  return 1
-  ;;
-esac
+    fi
+    return 1
+    ;;
+  esac
+fi
 
 while true; do
   clear
@@ -903,7 +924,8 @@
   print -r " the new completion system.\
 ${install_state[completion]:+  ($install_state[completion].)}
 
-(3)  Configure how keys behave when editing command lines.
+(3)  Configure how keys behave when editing command lines.\
+${install_state[bindkey]:+  ($install_state[bindkey].)}
 
 (4)  Pick some of the more common shell options.  These are simple on
      or off switches controlling the shell's features.  \
@@ -954,7 +976,7 @@
     if (( save )); then
       if [[ -f $zd/.zshrc ]]; then
 	cp $zd/.zshrc $zd/.zshrc.zni &&
-	print -r "Copied old '$zdd/.zshrc' to '$zdd/.zshrc.zni'.
+	print -r "Copied old '$zdmsg/.zshrc' to '$zdmsg/.zshrc.zni'.
 "
       fi
 



-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


This message has been scanned for viruses by BlackSpider MailControl - www.blackspider.com


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

* Re: PATCH: newuser system
  2005-11-25 10:24       ` Peter Stephenson
@ 2005-11-26 23:18         ` Bart Schaefer
  0 siblings, 0 replies; 14+ messages in thread
From: Bart Schaefer @ 2005-11-26 23:18 UTC (permalink / raw)
  To: zsh-workers

On Nov 25, 10:24am, Peter Stephenson wrote:
}
} This changes [initial keymap state], and also fixes the fact that
} actually if you didn't edit the recommended settings then they weren't
} saved.

Looks good, and that fixed another problem I had been about to report.

I have one remaining minor quibble:  Why is the default value of HISTFILE
set to ~/.histfile?  If you search the archives, it's "traditionally"
been ~/.zhistory since about 1996, with the occasional reference to
~/.zsh_history (which appears to have come about after Bash began using
~/.bash_history).  Not a big deal, but I've never seen ".histfile" before.


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

* Re: PATCH: newuser system
  2005-11-23 11:13 PATCH: newuser system Peter Stephenson
  2005-11-24  6:00 ` Bart Schaefer
@ 2005-11-29  1:58 ` Geoff Wing
  2006-02-18  8:42   ` newuser in 4.3.0-dev-4 (Was: PATCH: newuser system) Geoff Wing
  1 sibling, 1 reply; 14+ messages in thread
From: Geoff Wing @ 2005-11-29  1:58 UTC (permalink / raw)
  To: Zsh Hackers

On Wednesday 2005-11-23 22:13 +1100, Peter Stephenson output:
:The main thing I've been wanting before making test builds for the first
:4.3 release is a working zsh-newuser-install, otherwise it's not worth
:distributing the zsh/newuser module.
:
:Here's a first pass.  As this will be seen by a great many new users it
:really needs to be tested as widely as possible. 

I think it should abort in a couple of cases:
a) when run as root.  root should probably have to make his/her own changes
   manually (though maybe other people would think otherwise)
b) when we don't have write access to the HOME directory, say, after an su

Regards,
Geoff


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

* newuser in 4.3.0-dev-4 (Was: PATCH: newuser system)
  2005-11-29  1:58 ` Geoff Wing
@ 2006-02-18  8:42   ` Geoff Wing
  2006-02-18 12:57     ` Peter Stephenson
  0 siblings, 1 reply; 14+ messages in thread
From: Geoff Wing @ 2006-02-18  8:42 UTC (permalink / raw)
  To: zsh-workers

Geoff Wing <gcw@zsh.org> typed:
: I think it should abort in a couple of cases:
: a) when run as root.  root should probably have to make his/her own changes
:    manually (though maybe other people would think otherwise)
: b) when we don't have write access to the HOME directory, say, after an su

Currently, for "b)", I get the effect of "which zsh-newuser-install" to the
screen twice.

Regards,
Geoff


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

* Re: newuser in 4.3.0-dev-4 (Was: PATCH: newuser system)
  2006-02-18  8:42   ` newuser in 4.3.0-dev-4 (Was: PATCH: newuser system) Geoff Wing
@ 2006-02-18 12:57     ` Peter Stephenson
  2006-02-19  5:13       ` Geoff Wing
  0 siblings, 1 reply; 14+ messages in thread
From: Peter Stephenson @ 2006-02-18 12:57 UTC (permalink / raw)
  To: Zsh hackers list

Geoff Wing wrote:
> Geoff Wing <gcw@zsh.org> typed:
> : I think it should abort in a couple of cases:
> : a) when run as root.  root should probably have to make his/her own changes
> :    manually (though maybe other people would think otherwise)
> : b) when we don't have write access to the HOME directory, say, after an su
> 
> Currently, for "b)", I get the effect of "which zsh-newuser-install" to the
> screen twice.

I wasn't able to reproduce that.  I created a new user with zsh as the
login shell and the directory owned by root.  Nothing showed up.  Then I
changed the directory to the new user and tried again.  It ran the
script.

My guess is that somewhere there is some hairy interaction between
function definitions and the code in the newuser script which is what is
directly run by the zsh/newuser module:

if functions zsh-newuser-install >/dev/null 2>&1 ||
   autoload -U +X zsh-newuser-install; then
   zsh-newuser-install
fi

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page still at http://www.pwstephenson.fsnet.co.uk/


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

* Re: newuser in 4.3.0-dev-4 (Was: PATCH: newuser system)
  2006-02-18 12:57     ` Peter Stephenson
@ 2006-02-19  5:13       ` Geoff Wing
  2006-02-20 11:09         ` Peter Stephenson
  0 siblings, 1 reply; 14+ messages in thread
From: Geoff Wing @ 2006-02-19  5:13 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson <p.w.stephenson@ntlworld.com> typed:
:> Currently, for "b)", I get the effect of "which zsh-newuser-install" to the
:> screen twice.
: I wasn't able to reproduce that.

Ah, OK, I've broken it down to a badly written/parsed expression in my
/etc/zshrc which effectively does

	autoload -U
	autoload -U compinit
	compinit

with no function name in the first command.  Don't know what should happen
there.  Shouldn't it barf on it?  Anyway, doesn't cause any bad effects for
zsh-newuser-install for my normal user which already had $HOME/.z*

Regards,
Geoff


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

* Re: newuser in 4.3.0-dev-4 (Was: PATCH: newuser system)
  2006-02-19  5:13       ` Geoff Wing
@ 2006-02-20 11:09         ` Peter Stephenson
  0 siblings, 0 replies; 14+ messages in thread
From: Peter Stephenson @ 2006-02-20 11:09 UTC (permalink / raw)
  To: zsh-workers

Geoff Wing wrote:
> Peter Stephenson <p.w.stephenson@ntlworld.com> typed:
> :> Currently, for "b)", I get the effect of "which zsh-newuser-install" to th
> e
> :> screen twice.
> : I wasn't able to reproduce that.
> 
> Ah, OK, I've broken it down to a badly written/parsed expression in my
> /etc/zshrc which effectively does
> 
> 	autoload -U
> 	autoload -U compinit
> 	compinit
> 
> with no function name in the first command.  Don't know what should happen
> there.  Shouldn't it barf on it?

No, "autoload -U" is valid; autoload is historically derived from
functions -u which is derived from typeset -f... it's a little more
complicated nowadays since the options are different, but it's still the
case that running any of those commands with no non-option arguments
displays a list of whatever entity it is that has the specified flags
set, in this case autoloaded functions.

I'm a bit surprised to see it shows functions that have already been
autoloaded, however... it seems the presence of the -U flag makes it
(also) show functions that were previously autoloaded with that flag
set.  Conceivably this is useful.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


To access the latest news from CSR copy this link into a web browser:  http://www.csr.com/email_sig.php


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

end of thread, other threads:[~2006-02-20 11:10 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-11-23 11:13 PATCH: newuser system Peter Stephenson
2005-11-24  6:00 ` Bart Schaefer
2005-11-24  6:17   ` Clint Adams
2005-11-24  6:28   ` Danek Duvall
2005-11-24 11:42   ` Peter Stephenson
2005-11-24 18:20     ` Bart Schaefer
2005-11-25 10:24       ` Peter Stephenson
2005-11-26 23:18         ` Bart Schaefer
2005-11-24 18:52     ` Wayne Davison
2005-11-29  1:58 ` Geoff Wing
2006-02-18  8:42   ` newuser in 4.3.0-dev-4 (Was: PATCH: newuser system) Geoff Wing
2006-02-18 12:57     ` Peter Stephenson
2006-02-19  5:13       ` Geoff Wing
2006-02-20 11:09         ` Peter Stephenson

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).