esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% editfilename.MAC
#%NAME%
#   Macros allowing to enter a filename with filename expansion.
#
#%CATEGORY% Tools
#
#%DESCRIPTION%
#   This macro set allows to enter a filename with filename expansion.
#
#%LOG%
#   $Revision: 1.4 $ 
#   $Log: editfilename.mac,v $
#   Revision 1.4  2008/02/27 17:12:55  rey
#   documentation changes
#
#   Revision 1.3  2008/02/27 17:12:12  rey
#   documentation changs
#
#Revision 1.2  2007/08/09 16:15:57  witsch
#secure macros against existing macros coming with oscillation.mac
#Also there was a situation, where the path wouldn't be displayed
#correctly. This was due to lingering global variables, like "start".
#Secure these too. All variables and macros are now prefixed "_efn".
#
#Revision 1.1  2007/07/23 09:47:41  witsch
#Initial revision
#
##%END%

#%UU%(template)
#%MDESC% Enter a filename using filename expansion. %B%template%B% allows to
#preset a start directory (i.e. /data/id69).
def editfilename(template, max) '{
  unglobal _EFN[]
  global   _EFN[]

  _EFN["linebuffer"] = template == "" ? "/" : template
  _EFN["cursorpos"] = length (_EFN["linebuffer"]) # place the cursor at end of line
  # text might be longer than avaiable space 
  _EFN["start"] = 0; _EFN["currentpos"] = 0
  _EFN["maxlength"] = max ? max : COLS
  _efn_update_line

  local c ; c = ""
  
  while (c != "\n") {
    # wait for charater to be typed, used char-by-char input mode (-1)
    c = input (-1); while (asc(c) == 0) c = input (-1) 

    if (asc(c) == 27)  _efn_escape_sequence
    if (asc(c) == 8)   _efn_delete_char
    if (asc(c) == 127) _efn_delete_char
    if (asc(c) >= 32 && asc(c) < 127) _efn_insert_char(c)
#    if (asc(c) == 47)  { c = 9; _EFN["linebuffer"] = _EFN["linebuffer"] "/" }
    if (asc(c) == 21) {
      _EFN["linebuffer"] = "/"
      _EFN["cursorpos"] = 1
    } else if (asc(c) == 9) {
      global multiplechoice
      unix(sprintf("ls -Adb %s* 2>/dev/null", _EFN["linebuffer"]), multiplechoice)
      local aux[], many, len, i, dings, out
      len = length(_EFN["linebuffer"]) + 1
      many = split(multiplechoice, aux, "\n") - 1
      delete aux[many] # last line always empty
      unglobal multiplechoice
      for (i = 0; i < many; i++) {
        if (file_info(aux[i],"isdir")) {
          aux[i] = aux[i] "/"
        }
      }
      if (many == 1) {
        _EFN["linebuffer"]  = aux[0]
        len = length(_EFN["linebuffer"]) + 1
        _EFN["cursorpos"] = len - 1
        out = 1
      } else if (many == -1) { #nothing at all
        out = 1
      } else {
        print
        if (file_info(_EFN["linebuffer"],"isdir") && substr(_EFN["linebuffer"], len -1, 1) == "/") {
          dings = "cd " _EFN["linebuffer"] "; ls 2>/dev/null"
        } else {
          dings = "cd $(dirname " _EFN["linebuffer"]
          dings = dings "); ls -dbF $(basename " _EFN["linebuffer"] ")* 2>/dev/null"
        }
        unix(dings)
      }
      local firstc, followc
      while(!out) { #now check how far the names agree
        firstc = substr(aux[0], len, 1)
        for (i = 1; i < many; i++) {
          followc = substr(aux[i], len, 1)
          if (followc != firstc) {
            print
            out=1
            break
          }
        }
        if (out) {
          break
        }
        # this may only happen if all the members in aux have the 
        # same character in this position.
        _EFN["linebuffer"] = _EFN["linebuffer"] firstc
        len = length(_EFN["linebuffer"]) + 1
        _EFN["cursorpos"] = len - 1
      }
    }
    _efn_update_line
  }
  input (1) # back to line-by-line input mode (1)
  unglobal multiplechoice
  local retstr # get rid of all the global variables
  retstr = _EFN["linebuffer"]
  unglobal _EFN[]
  return retstr
}'

#%IU%
#%MDESC% used by "editline" and "editfilename"
def _efn_insert_char(c) '{
  part1 = substr (_EFN["linebuffer"],1,_EFN["cursorpos"])
  part2 = substr (_EFN["linebuffer"],_EFN["cursorpos"]+1)
  _EFN["linebuffer"] = part1 c part2 # concatenate strings
  _EFN["cursorpos"]++
}'

#%IU%
#%MDESC% used by "editline" and "editfilename"
def _efn_update_line '{
  _efn_scroll # make sure that cursor is within bounds
  # relative cursor positioning is done by adding an offset of 1000 or -1000
  tty_move(-1000-_EFN["currentpos"],1000)
  local text; text = substr(_EFN["linebuffer"],_EFN["start"]+1,_EFN["maxlength"])
  while (length(text) < _EFN["maxlength"]) text = text" " # pad with blanks
  printf ("%s",text)
  tty_move(-1000-length(text),1000)
  tty_move(1000+_EFN["cursorpos"]-_EFN["start"],1000)
  _EFN["currentpos"] = _EFN["cursorpos"]-_EFN["start"]
}'

#%IU%
#%MDESC% used by "editline" and "editfilename". Scroll text so cursor is within bounds
def _efn_scroll '{
  if (_EFN["cursorpos"] >= _EFN["start"]+_EFN["maxlength"]) _EFN["start"] = _EFN["cursorpos"]-_EFN["maxlength"]+1;
  if (_EFN["cursorpos"] < _EFN["start"]) _EFN["start"] = _EFN["cursorpos"];
}'

#%IU%
#%MDESC% used by "editline" and "editfilename". Decode VT100 escape sequences generated by the 
# cursor keys
def _efn_escape_sequence '{
  local c
  # wait for end of escape-seqence (always with upper-case letter)
  while (asc(c) < asc("A") || asc(c) > asc("Z")) c = input(-1)
  if (c == "C") _efn_cursor_right
  if (c == "D") _efn_cursor_left
  # ignore all other escape-codes
}'


#%IU%
#%MDESC% used by "editline" and "editfilename"
def _efn_delete_char '{
  if (_EFN["cursorpos"] > 0) {
    part1 = substr (_EFN["linebuffer"],1,_EFN["cursorpos"]-1)
    part2 = substr (_EFN["linebuffer"],_EFN["cursorpos"]+1)
    _EFN["linebuffer"] = part1 part2 # concatenate strings
    _EFN["cursorpos"]--
  }
}'

#%IU%
#%MDESC% used by "editline" and "editfilename"
def _efn_cursor_right 'if (_EFN["cursorpos"] < length (_EFN["linebuffer"])) _EFN["cursorpos"]++'

#%IU%
#%MDESC% used by "editline" and "editfilename"
def _efn_cursor_left 'if (_EFN["cursorpos"] > 0) _EFN["cursorpos"]--'

#%MACROS%
#%NO_IMACROS%
#%AUTHOR% H. Witsch%BR%
#  EDITFILENAME.MAC %BR%
#$Revision: 1.4 $, $Date: 2008/02/27 17:12:55 $
#%TOC%