home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-09-27 | 63.8 KB | 2,808 lines |
- # $Header: P:/source/ppee/macros/vi.pev 1.84 15 Jun 1990 17:50:32 JB $
-
- ##############################################################################
- #
- # Sage Software - POLYTRON Division
- # 1700 NW 167th Place
- # Beaverton, OR 97006
- #
- # Copyright 1990, Sage Software, Inc.
- #
- # Permission is hereby granted for licensed users of Sage Professional
- # Editor and PolyAwk to copy and modify this source code for their own
- # personal use. These derivative works may be distributed only to other
- # licensed Sage Professional Editor and PolyAwk users. All other usage
- # is prohibited without express written permission from Sage Software.
- #
- ##############################################################################
-
- #### $Workfile: vi.pel $: vi support keymaps and macros
-
- #### VI emulation mode release notes:
- #
- # EXTENSIONS:
- #
- # This editor is capable of editing multiple files at once. Thus it's
- # unnecessary to write the current file before switching to a new one,
- # nor is it necessary to process multiple files in strict sequential
- # order. ":n" switches to next buffer without writing file;
- # ":p"switches to the prev buffer; and ":e file" loads a new file or
- # switches to an existing buffer by that name -- all without requiring
- # files to be written at each step. The unnamed put buffer's contents
- # are not lost when buffer changes, thereby allowing cuts and pastes
- # between buffers without writing to intermediate files.
- #
- # This implementation allows empty files and files with incomplete last
- # lines to be edited. This is in contrast with VI, which prohibits
- # incomplete last lines and insists that there exist at least a single
- # newline character in the file.
- #
- # This implementation provides multiple windows. Each window may view
- # different parts of the same file or different files.
- #
- # The mouse can be used for all window operations, and for making text
- # selections. Vi operators apply to the selected text, if any, in lieu
- # of a vi motion. (Make a selection, then type "d" to delete it.) The
- # mouse allows column selections in addition to character- and line-
- # oriented ones.
- #
- # vi-style undo has been augmented by Sage's unlimited undo and redo.
- # <Alt-U> undoes and <Alt-Y> redoes. Also, vi's "U" command has been
- # extended to toggle between the fully edited and undone versions of
- # the current line, like "u" does for a single edit.
- #
- # This implementation always portrays a 100% accurate representation
- # of the text in the buffer. Standard vi employed "@" and "$" symbols
- # to indicate where text had been or would be deleted while minimizing
- # screen updates. This kludge is unnecessary and unsupported in this
- # implementation.
- #
- # Similarly, this editor is capable of scrolling horizontally, so long
- # lines are not wrapped. The redraw commands are not needed, so
- # <Ctrl-L> and <Ctrl-R> scroll left and right, respectively.
- #
- # Search commands have additional history associated with them.
- # Previous search patterns entered are accessable via vertical arrow
- # keys. The default is the most recently entered search pattern, same
- # as normal vi. One subtle difference is that the previous pattern is
- # visible on the command line. Patterns histories may be accepted by
- # pressing enter, or rejected by pressing escape. They also may be
- # edited with the DEL, backspace, and horizontal arrow keys. Newly
- # entered text overwrites the pattern unless an editing character has
- # been pressed first. Thus "/<Enter>" and "/newpattern<Enter>" work
- # exactly as before, although additional functionality is available as
- # a superset of previous key sequences.
- #
- # Rub-Out is a normal ASCII character, and does not cancel an insert.
- # ^C terminates an insert. Ctrl-Break resets the editor.
- #
- # ^V is only needed to quote keys that have a special meaning in insert
- # mode ( ^J ^M ^[ ^@ ^C ^D ^H ^W ^U ^V ). Other control
- # keys will self-insert, though they still can be quoted with ^V.
- #
- # The various forms of ^D are not required in insert mode.
- # Backspace unindents, and tab indents.
- #
- # The Ctrl-@ command in insert mode works for any previous insertion,
- # and is not limited to 128 chars. If typed as NOT the first character,
- # it inserts the previous insertion without terminating insert mode.
- #
- # Most of the native mode function- and Alt-keys are implemented for
- # convenience. Thus <Alt-W><Alt-Q> works like :wq
- #
- # Other special features, such as error-fix, word-processing, and "Code
- # Processing" support are available in VI mode via "<F10>command", and
- # other native key bindings.
- #
- # Code Processing template inserting is bound to the <F2> key during
- # insert mode.
- #
- # A new command is added: "g" goes to top of buffer if no address is
- # specified, otherwise goes to the specified line, like "G".
- #
- #
- # BUGS/OMISSIONS FIXED IN RELEASE 1.1:
- #
- # Numerous cursor positioning errors: $x $~ $bcw rx
- #
- # again (.) fixed for broken commands: rx sxx$
- #
- # repeat counts, eg.: 2dd.3.
- #
- # cw and cW now work correctly (differntly from dw and dW).
- #
- # correct cursor positioning after nS cc dd yyP and yyp
- #
- #
- # Known limitations of this emulation:
- #
- # Should allow cascaded searches: "/abc/;/def/"
- #
- # Positioning past EOL and EOF are sometimes off by one:
- #
- # "A^[" "Gj"
- #
- # Sentence motions should stop at paragraph and section breaks.
- #
- # The ":l" command and "l" suffix to ":g" and ":s" should work
- # differently from "p"
- #
- #
- # TODO LIST (to be implemented next):
- #
- # should use VI's regex syntax instead of our own
- #
- # Implement common :set commands.
- #
- # ":e %" and ":e #" and Ctrl-^ == ":e #"
- #
- # Precise modeling of VI's file/buffer status vs. :w :r :e :q commands;
- # appropriately issue "[new file]", "[Read only]" and other standard
- # messages for the following circumstances:
- #
- # buffer is modified
- # buffers are modified
- # new name; first write to existing file
- # partial write to existing file
- # read-only file/buffer
- #
- # semi-colons ";" separating ":" commands
- #
- # :map and :map! commands
- #
- # :abb command
- #
- #
- # ":m" -- block move command
- #
- # ":s" and ":g" commands should accept multi-line input
- #
- # ":g//i..." and ":g//a..." need to be implemented
- #
- # ":G" and ":V" commands ( :g or :v with prompt ).
- #
- # :n filename... command (use :p and :e instead)
- #
- # should prohibit motion past EOL of last line
- #
- # should prohibit having 0 lines in buffer
- #
- # Ctags commands: ^T => pop, ^] => tag; :ta file; :pop
- #
- # ^H/BS should be able to cancel ":", "/", and "?" command prompts
- #
- # :r !command :w !command
- #
- # :w >>file
- #
- #
- # OMISSIONS (likely never to be implemented):
- #
- # Several vi commands take a count to adjust the window size. Presently
- # all such counts are ignored, and, given the more robust windowing
- # capabilities, they are unlikely ever to be implemented. In some
- # cases, like searches, the counts may be changed to repeat counts.
- # Commands I know about (purportedly all "large motion" commands)...
- #
- # "z<num>." (change window size to <num>)
- #
- # ^D ^U ^F ^B / ? [[ ]] ` and '
- #
- # maybe: ^E ^Y n N
- #
- # # -- macro character -- substitute for FN keys on keyboards w/out
- #
- # @ macro commands
- #
- # & command -- "synonym for :& by analogy with ex &" (??)
- #
- # nO -- opens n lines
- #
- # lisp mode commands: "(", ")", "{", "}", "="
- #
- ####
-
- ### local variables
-
- ## vi keymaps:
-
- local vi_command_keymap = -1
- local vi_insert_keymap = -1
-
-
- ## vi constants:
-
- local DEFAULT_BID = "1" # default buffer id if not explicitly spec'd
- local LINE_BUFFER = 0x80000 # user buffer flag for line mode buffers
- local AND_DELETE = 1 # optional arg to vi_yank()
- local DEFAULT_ONE = 1 # optional arg to ex_ and select_range()
- #local DONT_DELETE = 0 # optional arg to vi_yank()
- local SEARCH_HIST = "SEARCH" # history index for "/" and "?" commands
- local NEWLINE_BEFORE = 1 # insert flag -- put newline before or
- local NEWLINE_AFTER = 2 # -- after current line
-
- local ALT_KEY = 0x08 # alt key flag
- local CTRL_AT = 768 # <Ctrl-@> keycode
- local ENTER_KEY = 7181
-
- #local vi_exact_mark = "`" # syntax for exact mark motion
- local vi_line_mark = "'" # syntax for line mark motion
- # block of reserved marks (ugh!!)
- local vi_major_mark = 909 # place from which last major motion moved
- local vi_base_mark = 910 # named marks -- first is "''" / "``"
-
- local DONT_MARK = 2 # op_type_2b() arg to suppress mark_context()
- local MAJOR_MARK = 1 # op_type_2b() arg mark major motion
-
-
- ## vi emulation internal states:
-
- local pending_operator # name of pending operator, if any
-
- local number_register = 0 # number register used to repeat commands
-
- local vi_read_name # file name in last read command
- local in_glob # executing a :g or :v command
- local browser_bid = 0 # buffer containing ":" command's "printed" output
-
- local buf_id # selected get/put buffer
- local buf_id_map # maps buf_id names to buffer handles
-
- local vi_search_dir # previous search direction for search_again
- local vi_search_flags # vi search flags
-
- local vi_find_com # last find command, if any
- local vi_find_char # last find character, if any
-
- # address ranges for ":" commands:
-
- local ex_addr1 # first address if any
- local ex_addr2 # second address if any
- local ex_addresses = 0 # count of addresses supplied
- local ex_com # command string being parsed
-
- local line_search # signal from ex_address() to vi_search_key()
-
- # state vars for vi-style undo and "."/again:
-
- local undo_baseline # undo indicies to undo previous command
- local undo_line_baseline # undo indicies to undo all changes to...
- local undo_line # ...the current line (remembered here)
-
- local again_string # playback string to re-execute last command
- local tmp_again # interim version of again_string
- local playing_again = 0 # flag for insert, et al.
-
- local prev_number_register = 1 # previous repeat count
- local prev_buf_id # previous buf id
- local prev_mark_id # previous mark id
- local vi_r_ch # previous "r" command replacement string
-
-
- ## vi mode user-visible external states, flags and modes
-
- local vi_ai_mode = 1 # vi auto indent mode
-
-
- ### vi emulation
- #
-
- ## vi -- enter vi mode
- #
- function vi(){ #PUBLIC #VOID
-
- emulation_mode = "vi"
-
- # Misc. items...
-
- visible_end_buffer = default_visible_end_buffer = ""
- visible_virtual_lines = default_visible_virtual_lines = "~"
- color_errors = color_warnings = color_text
-
- # default_page_overlap =
- window_page_overlap = 2
-
- vi_search_flags = search_flags \
- = SEARCH_REGEX \
- + SEARCH_MAXIMAL_MATCH \
- + SEARCH_WRAPS \
- + SEARCH_ADVANCE \
- # + SEARCH_IGNORE_CASE
-
- buffer_flags = default_buffer_flags \
- = or( default_buffer_flags, \
- BUFFER_REAL_SPACE_ONLY \
- + BUFFER_WHOLE_LINES )
-
- toggle_dialog( 1 )
- toggle_electric( 1 )
-
- create_vi_keymaps()
- vi_command_mode() # vi starts in command mode
- }
-
-
- ## entering vi command mode
- #
- # This gets called at the conclusion of insert mode, after all errors,
- # after all "operators", and after each "ex" command.
- #
- local function vi_command_mode(){
-
- # reset to normal state
-
- current_keymap = vi_command_keymap
- number_register = 0 # calling use_number() overwrites prev num
- buf_id = DEFAULT_BID
- in_glob = 0
- op_flush()
-
- # if( current_line_length > 0 \
- # && current_line_length <= current_line_offset )
- # prev_char()
- }
-
- ## indicate a common error
-
- function vi_beep( s ){
- beep()
- pending_operator = "" # cancel any pending operator
- vi_command_mode() # reset to command mode
- error( s ) # cause longjump to editor top-level
- # ( "never" returns )
- }
-
- function establish_baseline(){
- undo_baseline[ current_buffer ] = undo_index()
-
- # message( "baseline: " undo_index())
- if( undo_line[ current_buffer ] != current_line ){
- undo_line[ current_buffer ] = current_line
- undo_line_baseline[ current_buffer ] = undo_index()
- }
- }
-
- function vi_undo_redo( baseline ){
- local new, old
-
- # message( "undo/redo: " undo_index())
- if( current_buffer in baseline ){
- new = baseline[ current_buffer ]
- baseline[ current_buffer ] = old = undo_index()
-
- if( new < old )
- undo( new )
- else
- redo( new )
- } else {
- vi_beep()
- }
- }
-
- function vi_undo(){
- vi_undo_redo( undo_baseline )
- }
-
- function vi_undo_line(){
- if( undo_line[ current_buffer ] == current_line )
- vi_undo_redo( undo_line_baseline )
- else
- vi_beep()
- }
-
- function vi_again(){
- local i, ch
-
- if( !again_string )
- vi_beep()
-
- if( prev_buf_id ~ /[1-8]/ )
- prev_buf_id = chr( ord( prev_buf_id ) + 1 )
- buf_id = prev_buf_id
-
- if( !number_register )
- number_register = prev_number_register
-
- playing_again = 1
- playback( again_string )
- playing_again = 0
- }
-
-
- # setup for a single-char command, like "Y" or "~".
- #
- # Generate an error if there is a pending operator.
- # Record the appropriate information for undo and again.
- # Special case "single-char" commands like "[[" and "]]" must
- # manually insert an extra record_op()
-
- local function op_type_1(){
- operator_disallowed()
- prev_number_register = number_register
- establish_baseline()
- record_op()
- op_wrap()
- }
-
- # setup for the first of a two-char operator command, like "dW" or "yy":
- #
- # Record the appropriate information for undo and again.
-
- local function op_type_2a(){
- prev_number_register = number_register
- record_op()
- establish_baseline()
- }
-
- # setup for a motion that might be paired with a two-char operator.
- # like "!}" or ">w" (may or may not be paired with an operator):
- #
- # Record the appropriate information for undo and again.
-
- local function op_type_2b( context_type ){
- if( pending_operator )
- prev_number_register = number_register
-
- if( tmp_again )
- record_op()
-
- mark_context( context_type )
- }
-
- # wrap-up for the successful completion of any command
-
- local function op_wrap(){
- if( tmp_again ){
- prev_buf_id = buf_id
- again_string = tmp_again
- tmp_again = ""
- }
- }
-
- # cancel command history accumulated thus far
-
- local function op_flush(){
- tmp_again = ""
- }
-
- # record a key into the again string
-
- local function record_op( key ){
- if( !argcount())
- key = current_key
-
- if( key == 0 )
- key = CTRL_AT
-
- tmp_again = tmp_again chr( key ) chr( shiftr( key, 8 ))
- }
-
-
- ## a numeric count may preceed most commands.
- #
- # leading zeros are illegal ("0" is a command, executed here).
- # no count means 1.
- # the count is reset after every command, whether the count is used or not.
- # a copy of the previous count is maintained for vi_again
-
- function vi_digit(){
- local key = and( current_key, 0xF )
-
- if( number_register )
- number_register = number_register * 10 + key
- else
- if( key )
- number_register = key
- else
- vi_goto_bol()
- }
-
- local function use_number(){
- local prev = number_register
-
- if( prev == 0 )
- prev = 1
-
- number_register = 0
-
- return prev
- }
-
- local function disallow_number(){
- if( number_register != 0 )
- warning( "count ignored with this command" )
- number_register = 0
- }
-
- local function vi_getc(){
- local ch = getkey()
-
- if( and( ch, 255 ))
- return chr( ch )
- vi_beep()
- }
-
-
-
- ### vi operators
-
- # process operator command
- #
- # if first one and no selection then remember it pending next motion
- # if first one and existing selection, execute operator
- # if second one matches previous one, execute operator in line mode
- # else error
-
- function vi_operator(){
- local ch = chr( and( current_key, 255 )) # get operator
-
- op_type_2a()
-
- if( pending_operator ){
- if( ch == pending_operator ){
- select_lines( use_number())
- xeq_op() # operate on lines
- } else
- vi_beep() # operator mismatch
- } else if( region_type()){
- pending_operator = ch # operate on selection
- xeq_op()
- # !! can't do again
- } else
- pending_operator = ch # remember for later
- }
-
- local function operator_disallowed(){
- tmp_again = "" # avoids problem w/vi_space, etc
- # followed by "."
- if( pending_operator )
- vi_beep() # never returns
- }
-
- # manually insert an operator
- #
- # usage: "pend_operator( op ); motion()"
- #
- local function pend_operator( op ){
- operator_disallowed()
- pending_operator = op
- }
-
- # process pending operator, if any
- #
- # mode specifies the mode of the operation: line, normal, or inclusive
- # if a region has already been selected, mode is ignored
-
- local function xeq_op( mode ){
- local rt
- local line
-
- if( pending_operator ){
-
- if( !argcount())
- mode = NORMAL_SELECTION
-
- op_wrap()
-
- if(( rt = region_type()))
- mode = rt
- else {
- drop_anchor( mode )
- goto_mark( vi_base_mark )
- }
-
- if( pending_operator == "y" ){
- vi_yank()
- raise_anchor()
-
- } else if( pending_operator == "d" ){
- vi_yank( AND_DELETE )
- if( mode == LINE_SELECTION )
- skip_whitespace()
-
- } else if( pending_operator == "c" ){
- vi_yank( AND_DELETE )
- vi_insert(( mode == LINE_SELECTION ) \
- ? NEWLINE_BEFORE \
- : 0 )
-
- } else if( pending_operator == "<" ){
- outdent_tabs()
- raise_anchor()
-
- } else if( pending_operator == ">" ){
- indent_tabs()
- raise_anchor()
-
- } else if( pending_operator == "!" ){
- vi_filter()
- raise_anchor()
-
- } else
- vi_beep( "bad VI operator: " pending_operator )
-
- pending_operator = ""
-
- } else
- op_flush()
-
- vi_command_mode()
- }
-
-
-
- ### yank/put buffers & associated stuff
-
-
- # select n lines, starting with the current
-
- local function select_lines( n ){
- local target = current_line + n - 1
-
- create_mark( TEMP_MARK )
- if( n > 1 ){
- current_line = target
-
- if( current_line != target ){
- goto_mark( TEMP_MARK )
- vi_beep() ## "too few lines remain in buffer" )
- }
- }
-
- drop_anchor( LINE_SELECTION )
- goto_mark( TEMP_MARK )
- }
-
- local function move_down( n ){
- local target = current_line + n
-
- create_mark( TEMP_MARK )
- current_line = target
- if( current_line != target ){
- goto_mark( TEMP_MARK )
- vi_beep() ## "too few lines remain in buffer" )
- }
- }
-
- # select n characters, n>0 => select towards EOL; n<0 => select towards BOL
- # error if selection bypasses BOL or EOL
- # n=0 => error
-
-
- local function select_chars( n ){
- if( n > 0 && current_line_length - current_line_offset >= n ){
- drop_anchor( NORMAL_SELECTION )
- next_char( n )
- } else if( n < 0 && current_line_offset >= -n ){
- drop_anchor( NORMAL_SELECTION )
- prev_char( -n )
- } else
- vi_beep()
- }
-
- # prompt for buffer id
-
- function vi_bufid_key(){
- local ch = vi_getc()
-
- if( ch ~ /[a-zA-Z1-9]/ ) # buffer id "@" is also used internally
- buf_id = ch
- else
- vi_beep()
- }
-
- # returns a buffer id of a system buffer associated with the current buf_id
- # if clear is true, the buffer returned is empty.
- #
- local function yank_bid( put, del ){
- local bid = tolower( buf_id )
- local buf, i, b2, b1
-
- if( bid in buf_id_map ){ # we're reusing an existing buffer:
- if( bid == DEFAULT_BID && del ){
- # save 9 most recent deletes:
- if( "9" in buf_id_map )
- delete_buffer( buf_id_map[ "9" ])
- for( i = 9; i > 1; i-- ){
- b2 = "" i
- b1 = "" i - 1
- if( b1 in buf_id_map )
- buf_id_map[ b2 ] = buf_id_map[ b1 ]
- }
- # and fall to the return to create the new one
- } else {
- if( put || isupper( buf_id )) # upper=> append # !del ||
- return buf_id_map[ bid ]
- else
- # we're reusing a bid and need it to be empty
- delete_buffer( buf_id_map[ bid ])
- # and we fall through to create an empty one
- }
-
- } else if( put )
- vi_beep( "Nothing has been put in buffer \"" buf_id )
-
- return ( buf_id_map[ bid ] = create_buffer( "vi_yank_" bid, "", BUFFER_SYSTEM ))
- }
-
- # yank or delete the current selection into the current "put" buffer
- #
- # this is the yank command, and also used by other commands.
-
- function vi_yank( del ){
- local prev = current_buffer
- local line = ( region_type() == LINE_SELECTION )
-
- if( del )
- delete_to_scrap()
- else {
- copy_to_scrap()
- raise_anchor()
- }
-
- current_buffer = yank_bid( 0, del )
-
- if( line )
- buffer_flags = or( buffer_flags, LINE_BUFFER )
- else
- buffer_flags = and( buffer_flags, not( LINE_BUFFER ))
-
- insert_scrap()
- current_buffer = prev
-
- return line
- }
-
- # put the current yank buffer's contents into the scrap buffer,
- # and return true if the buffer was a "LINE" buffer.
- #
- # Most clients need to perform some fine positioning
- # depending on the line status, before actually inserting the text.
- # Hence the obscure nature of this function.
- #
- local function put_buffer_to_scrap(){
- local prev = current_buffer
- local line_oriented
-
- current_buffer = yank_bid( 1, 0 )
-
- goto_buffer_top()
- drop_anchor()
- goto_buffer_bottom()
- copy_to_scrap()
- raise_anchor()
-
- line_oriented = and( buffer_flags, LINE_BUFFER )
- current_buffer = prev
-
- return line_oriented
- }
-
- # local function insert_put_buffer( id ){
- # buf_id = id
- # put_buffer_to_scrap()
- # insert_scrap()
- # }
-
- function vi_Y(){ # yank lines
- op_type_1()
- select_lines( use_number())
- vi_yank()
- }
-
- function vi_p(){ # put after cursor/line
- local lnum, lines
-
- op_type_1()
- if(( lines = put_buffer_to_scrap())){
- down()
- goto_bol()
- lnum = current_line
- } else
- right()
-
- insert_scrap()
-
- if( lines )
- vi_goto_line( lnum )
- else
- prev_char()
- }
-
- function vi_P(){ # put before cursor/line
- local lnum, lines
-
- op_type_1()
- if(( lines = put_buffer_to_scrap())){
- goto_bol()
- lnum = current_line
- }
-
- insert_scrap()
-
- if( lines )
- vi_goto_line( lnum )
- else
- prev_char()
- }
-
-
- ### insert mode and auxiliary operations
-
- local insert_index
- local insert_offset
- local insert_text
-
- local function vi_insert( newline ){
- local n, count, col, start_line, line, offset
-
- count = use_number()
-
- if( playing_again ){
- if( and( buffer_flags, BUFFER_OVERTYPE_MODE ))
- delete_chars( length( insert_text ))
-
- reinsert_string( insert_text )
-
- } else {
-
- # insert requested newlines
-
- if( newline ){
- if( newline == NEWLINE_BEFORE )
- vi_ai_b4()
- else
- vi_ai_nl()
- insert_text = "\n"
- } else
- insert_text = ""
-
- # remember starting position:
-
- insert_index = undo_index()
- start_line = current_line
- insert_offset = buffer_offset
-
- current_keymap = vi_insert_keymap
-
- message( "[ insert mode ]" )
- process_begin() # interpret insert keymap
- message( "" )
-
- # copy inserted text to insert_text
-
- if( current_line == start_line ){
- insert_text = insert_text \
- read_buffer( insert_offset - buffer_offset )
- } else {
- line = current_line - 1
- offset = buffer_offset
- goto_buffer_offset( insert_offset )
-
- insert_text = insert_text read_buffer()
- current_column = 0
-
- while( current_line++ < line )
- insert_text = insert_text "\n" read_buffer()
-
- goto_buffer_offset( offset )
- insert_text = insert_text "\n" read_buffer( -current_line_offset )
- }
- }
-
- # process repeat count, if any
-
- while( count-- > 1 )
- reinsert_string( insert_text )
-
- if( current_column > 1 )
- prev_char()
-
- vi_command_mode()
- }
-
-
- # properly auto-indent reinserted text
- # (if auto-indent is disabled, this is the same as insert_string())
-
- local function reinsert_string( text ){
- local i, line, s, n
-
- n = split( text, line, "\n" )
-
- for( i = 1; i<= n; i++ ){
- s = line[ i ]
-
- if( i > 1 )
- sub( /^[ \t]+/, "", s )
-
- insert_string( s )
-
- if( i < n )
- vi_ai_cr()
- }
- }
-
-
- # compute the buffer offset such that it is either
- #
- # a. the starting point of the insert (insert_offset), or
- # b. the BOL of the current line (buffer_offset - current_line_offset)
- #
- # -- whichever is closer to buffer_offset
- #
- local function insert_backstop(){
- local offset = buffer_offset - current_line_offset
-
- return offset < insert_offset ? insert_offset : offset
- }
-
-
- function vi_insert_bs(){
- if( insert_backstop() < buffer_offset )
- backspace()
- else
- beep()
- }
-
- # "dB", limited by scope of current indent
-
- function vi_insert_dB(){
- local offset = insert_backstop()
- local sflags = SEARCH_REGEX + SEARCH_MAXIMAL_MATCH \
- + SEARCH_ADVANCE + SEARCH_BACKWARD
-
- if( buffer_offset <= offset )
- beep()
- else {
- drop_anchor( NORMAL_SELECTION )
-
- if( search( WORD_patt, sflags )){
- if( buffer_offset < offset )
- goto_buffer_offset( offset )
- delete_chars()
- }
- }
- }
-
- function vi_insert_cancel(){
- undo( insert_index )
- }
-
-
- function vi_insert_quoted(){
- local ch
-
- message( "type ascii key to be inserted" )
-
- ch = getkey()
-
- if( and( ch, 255 ) || ch == CTRL_AT ){
- insert_key( ch )
- message( "" )
- } else
- warning( "Can't insert non-ascii keys" )
- # error() would screw-up insert mode
- }
-
- function vi_insert_unindent(){
- local ch = read_buffer( -1 )
-
- if( ch == "^" || ch == "0" ){ # no way for ^^D to save for next
- goto_bol()
- drop_anchor( NORMAL_SELECTION )
- goto_eol()
- delete_chars()
-
- } else if( ch == "" || ch == "\t" || ch == " " ){
- vi_insert_bs()
- } else
- beep()
- }
-
- function vi_reinsert(){
- local flag = ( insert_backstop() < buffer_offset )
-
- reinsert_string( insert_text )
-
- if( !flag )
- process_end()
-
- # a more accurate implementation would beep if !flag
- # and always process_end() the insert; this is an extension
- }
-
-
- ## vi auto-indent mode:
- #
- # vi ai mode is different from electric (a) because normal ai is
- # broken in non-virtual space mode, and (b) because vi auto-indent
- # works differently.
-
- function vi_ai_b4(){
- if( current_line == 1 ){
- goto_bol()
- insert_newline()
- up()
- } else {
- up()
- vi_ai_nl()
- }
- }
-
- function vi_ai_nl(){
- goto_eol()
- vi_ai_cr()
- }
-
-
- function vi_ai_cr( repeat ){
-
- insert_string( "\n" )
-
- if( vi_ai_mode ){
- prev_line()
- drop_anchor()
- goto_bol()
- copy_to_scrap()
- raise_anchor()
- down()
- insert_scrap()
- }
- }
-
-
- ### insertion commands
-
- function vi_i(){
- op_type_1()
-
- vi_insert()
- }
-
- function vi_I(){
- op_type_1()
-
- skip_whitespace()
- vi_insert()
- }
-
-
- function vi_a(){
- op_type_1()
-
- if( current_line_length > current_line_offset )
- right()
- vi_insert()
- }
-
- function vi_A(){
- op_type_1()
-
- goto_eol()
- vi_insert()
- }
-
-
- function vi_o(){
- op_type_1()
-
- vi_insert( NEWLINE_AFTER )
- }
-
- function vi_O(){
- op_type_1()
-
- vi_insert( NEWLINE_BEFORE )
- }
-
- ### deletions
- #
- # all deletions delete_to_scrap() even if single character
-
-
- function vi_X(){
- op_type_1()
-
- select_chars( -use_number())
- vi_yank( AND_DELETE )
- }
-
- function vi_x(){
- op_type_1()
-
- select_chars( use_number())
- vi_yank( AND_DELETE )
-
- if( current_line_length <= current_line_offset \
- && current_line_offset )
- prev_char()
- }
-
- ## more complex edits -- combinations of delete/insert
-
- function vi_J(){
- local n = use_number()
- local ins
-
- op_type_1()
-
- if( n > 1 )
- n -= 1
-
- while( n-- > 0 ){
- goto_eol()
- while( read_buffer( -1 ) ~ /[ \t]/ )
- prev_char()
-
- ins = ( read_buffer( -1 ) == "." ) ? " " : " "
-
- drop_anchor()
- next_line()
- vi_yank( AND_DELETE )
-
- if( read_buffer( 1 ) != "(" ){
- insert_string( ins )
- }
- }
- }
-
- function vi_D(){
- op_type_1()
- pend_operator( "d" )
- vi_goto_eol()
- }
-
- function vi_C(){
- vi_D()
- vi_insert()
- }
-
- function vi_R(){
- op_type_1()
- buffer_flags = or( buffer_flags, BUFFER_OVERTYPE_MODE )
- vi_insert()
- buffer_flags = xor( buffer_flags, BUFFER_OVERTYPE_MODE )
- }
-
- function vi_r( ){
- local n
-
- op_type_1()
-
- n = use_number()
-
- # limit scope to current line
-
- if( current_line_length - current_line_offset < n )
- vi_beep()
-
- if( !playing_again )
- vi_r_ch = vi_getc()
- if( vi_r_ch == "\r" || vi_r_ch == "\n" )
- vi_r_ch = "\n"
-
- select_chars( n )
- vi_yank( AND_DELETE )
-
- if( vi_r_ch == "\n" ){
- while( n-- > 0 )
- vi_ai_cr()
- } else {
- while( n-- > 0 )
- insert_string( vi_r_ch )
-
- if( current_column > 1 )
- prev_char()
- }
- }
-
- function vi_S(){
- op_type_1()
-
- select_lines( use_number())
- vi_yank( AND_DELETE )
- vi_insert( NEWLINE_BEFORE )
- }
-
- function vi_s(){
- op_type_1()
-
- select_chars( use_number())
- vi_yank( AND_DELETE )
- vi_insert()
- }
-
- function vi_tilde(){
- op_type_1()
-
- select_chars( use_number())
- reverse()
- raise_anchor()
-
- if( current_line_length <= current_line_offset \
- && current_line_offset )
- prev_char()
- }
-
- ### vi motion commands
-
- local function vi_goto_line( line ){
- current_line = line
- skip_whitespace()
- }
-
- function vi_goto( n ){
- op_type_2b( MAJOR_MARK )
-
- if( number_register )
- n = use_number() # need a range check
- else
- if( !n )
- n = buffer_last_line - 1
-
- vi_goto_line( n )
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_left(){
- local n = use_number()
-
- if( current_line_offset < n )
- vi_beep()
-
- op_type_2b()
- prev_char( n )
- xeq_op()
- }
-
- function vi_right(){
- local n = use_number()
-
- if( current_line_length - current_line_offset <= n )
- vi_beep()
-
- op_type_2b()
- next_char( n )
- xeq_op()
- }
-
- local vert_column
- local vert_motion
-
- function vi_up(){
- local n = use_number()
-
- if( current_line <= n )
- vi_beep()
-
- op_type_2b()
- up( n )
-
- if( prev_command != vert_motion)
- vert_column = current_column
- else
- current_column = vert_column
- vert_motion = current_command
-
- if( and( buffer_flags, BUFFER_POSITION_IS_VIRTUAL ))
- prev_char()
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_down(){
- local n = use_number()
-
- op_type_2b()
- move_down( n )
-
- if( prev_command != vert_motion)
- vert_column = current_column
- else
- current_column = vert_column
- vert_motion = current_command
-
- if( and( buffer_flags, BUFFER_POSITION_IS_VIRTUAL ))
- prev_char()
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_space(){
- if( region_type()){
- operator_disallowed()
- if( and( keyboard_flags, ALT_KEY ))
- outdent_columns()
- else
- indent_columns()
- } else
- vi_right()
- }
-
- function vi_bksp(){
- if( region_type()){
- operator_disallowed()
- outdent_columns()
- } else
- vi_left()
- }
-
- function vi_tab(){
- if( region_type()){
- operator_disallowed()
- if( and( keyboard_flags, ALT_KEY ))
- outdent_tabs()
- else
- indent_tabs()
- } else
- vi_beep()
- }
-
- function vi_back_tab(){
- if( region_type()){
- operator_disallowed()
- outdent_tabs()
- } else
- vi_beep()
- }
-
-
- function vi_goto_column(){
- local n = use_number()
-
- if( current_line_width < n )
- vi_beep()
-
- op_type_2b()
- current_column = n
- xeq_op()
- }
-
- function vi_H(){
- local n = use_number() - 1
-
- op_type_2b( MAJOR_MARK )
-
- goto_window_top()
- if( n >= window_text_height )
- n = window_text_height - 1
- down( n )
- skip_whitespace()
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_M(){
- disallow_number()
- op_type_2b( MAJOR_MARK )
-
- goto_window_middle()
- skip_whitespace()
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_L(){
- local n = use_number() - 1
-
- op_type_2b( MAJOR_MARK )
-
- goto_window_bottom()
- if( n >= window_text_height )
- n = window_text_height - 1
- up( n )
- skip_whitespace()
-
- xeq_op( LINE_SELECTION )
- }
-
- function vi_goto_bol(){
- disallow_number()
-
- op_type_2b()
- goto_bol()
- xeq_op()
- }
-
- function vi_goto_eol(){
- local n = use_number()
-
- op_type_2b()
- if( n > 1 )
- down( n - 1 )
- current_column = current_line_width # goto_eol()
- xeq_op( INCLUSIVE_SELECTION )
- }
-
- function vi_next_line(){
- local n = use_number()
-
- op_type_2b()
- next_line( n )
- xeq_op( LINE_SELECTION )
- }
-
- function vi_prev_line(){
- local n = use_number()
-
- op_type_2b()
- prev_line( n )
- xeq_op( LINE_SELECTION )
- }
-
- function vi_skip_whitespace(){
- local n = use_number()
-
- op_type_2b()
- skip_whitespace()
- xeq_op()
- }
-
- function vi_goto_matching(){
- local n = use_number()
-
- op_type_2b( MAJOR_MARK )
- if( read_buffer( 1 ) !~ /[(){}[\]]/ )
- if( match( read_buffer(), "[(){}[\\]]" ))
- next_char( RSTART - 1 )
- else
- vi_beep()
-
- goto_matching()
- xeq_op( INCLUSIVE_SELECTION )
- }
-
-
-
- # Word, sentence, paragraph, and section motions.
- # Different commands call vi_motion with one of the patterns below.
- #
- # Different dialects of vi implement subtle variations for certain combos:
- #
- # Commands..... SPE MKS Sun AIX
- #
- # !w >W etc. yes yes error error
- #
- # w W b B over \n skips skips stops error
- # \n \n at \n
- #
- #
- # add "|^[ \t]*$" to word_, WORD_, end_, and END_patt to make these
- # motions treat newlines as words, ala Sun vi.
-
-
- local word_patt = "[a-z0-9A-Z_]+|[^a-z0-9A-Z_ \t]+"
- local WORD_patt = "[^ \t]+"
- local end_patt = "[ \t]*([a-z0-9A-Z_]+|[^a-z0-9A-Z_ \t]+)\\c"
- local END_patt = "[ \t]*[^ \t]+\\c"
- local sent_patt = "(\\.|!|\\?)[)\"'\\]]*( |$)"
- local para_patt = "^$|^\\.PP$|^\\.NH|^\\.IP|^\\.LP|^\\.PP|^\\.QP|^\\.LI"
- local sect_patt = "^\\.NH|^\\.SH|^\\.H([ \t]|$)|^\\.HU|^\\{|^function|^local[ \t]+function|^global[ \t]+function|^\f"
-
-
- local function vi_motion( patt, direction, special ){
- local sflags = SEARCH_REGEX + SEARCH_MAXIMAL_MATCH + SEARCH_ADVANCE
- local count
-
- search_count = count = use_number()
- op_type_2b( MAJOR_MARK )
-
- save_position()
-
- if( count != search( patt, direction + sflags )){
- restore_position( 1 )
- vi_beep()
- }
-
- restore_position( 0 )
- }
-
-
- function vi_w( patt ){
-
- if( !argcount())
- patt = word_patt
-
- if( pending_operator ~ /[ycd]/ )
- patt = patt "|$"
-
- if( pending_operator == "c" ){
- vi_cw( patt )
-
- } else {
- vi_motion( patt, SEARCH_FORWARD )
- xeq_op( NORMAL_SELECTION )
- }
- }
-
- function vi_cw( patt ){
- local ch = read_buffer( 1 )
-
- vi_motion( patt, SEARCH_FORWARD )
-
- if( ch !~ /[ \t]/ )
- search( "[^ \t]\\c", SEARCH_REGEX + SEARCH_ADVANCE )
-
- xeq_op( NORMAL_SELECTION )
-
- }
-
- function vi_W(){
- vi_w( WORD_patt )
- }
-
- function vi_e(){
- vi_motion( end_patt, SEARCH_FORWARD )
- prev_char()
- xeq_op( INCLUSIVE_SELECTION )
- }
-
- function vi_E(){
- vi_motion( END_patt, SEARCH_FORWARD )
- prev_char()
- xeq_op( INCLUSIVE_SELECTION )
- }
-
- function vi_B(){
- vi_motion( WORD_patt, SEARCH_BACKWARD )
- xeq_op( NORMAL_SELECTION )
- }
-
- function vi_b(){
- vi_motion( word_patt, SEARCH_BACKWARD )
- xeq_op( NORMAL_SELECTION )
- }
-
- function vi_prev_sent(){
- local sflags = SEARCH_BKWD_REGEX_ADV + SEARCH_MAXIMAL_MATCH
- local count = use_number() + 1
-
- op_type_2b( MAJOR_MARK )
-
- search_count = count
- if( search( sent_patt, sflags ) == count )
- next_word()
- else
- goto_buffer_top()
-
- xeq_op( NORMAL_SELECTION )
- }
-
- function vi_next_sent(){
- vi_motion( sent_patt, SEARCH_FORWARD )
- next_word()
- xeq_op( NORMAL_SELECTION )
- }
-
- function vi_prev_para(){
- vi_motion( para_patt, SEARCH_BACKWARD )
- if( pending_operator )
- current_line--
- xeq_op( LINE_SELECTION )
- }
-
- function vi_next_para(){
- vi_motion( para_patt, SEARCH_FORWARD )
- if( pending_operator )
- current_line--
- xeq_op( LINE_SELECTION )
- }
-
- function vi_prev_sect(){
- record_op() # see op_type_1()
- disallow_number() # removing this would be a useful EXTENSION
- vi_motion( sect_patt, SEARCH_BACKWARD )
- if( pending_operator )
- current_line--
- xeq_op( LINE_SELECTION )
- }
-
- function vi_next_sect(){
- record_op() # see op_type_1()
- disallow_number() # removing this would be a useful EXTENSION
- vi_motion( sect_patt, SEARCH_FORWARD )
- if( pending_operator )
- current_line--
- xeq_op( LINE_SELECTION )
- }
-
-
-
-
- ## vi "find" commands
- # fx skip forward to character "x"
- # Fx skip backwards to character "x"
- # tx skip forwards to just before character "x"
- # Tx backwards just before "x"
- # ; repeat last find command
- # , execute last find command in reverse direction
-
- function vi_find_repeat(){
- vi_find_it( vi_find_com )
- }
-
- function vi_find_reverse(){
- local com = toreverse( vi_find_com )
- vi_find_it( com )
- }
-
- function vi_find(){
- vi_find_com = chr( current_key )
- vi_find_it( vi_find_com, 1 )
- }
-
- local function vi_find_it( com, needChar ){
- local i, n
-
- op_type_2b( MAJOR_MARK )
-
- if( needChar ) ## !playing_again && )
- vi_find_char = vi_getc()
-
- if( !vi_find_char )
- vi_beep()
-
- n = use_number()
-
- while( n-- > 0 ){
- if( islower( com )){ # forwards
- i = index( substr( read_buffer(), 2), vi_find_char )
- if( i )
- next_char( i - ( com == "t" ))
- } else { # backwards
- i = bindex( read_buffer( - current_column ), vi_find_char )
- if( i )
- prev_char( i - ( com == "T" ))
- }
- }
- if( !i )
- vi_beep()
-
- xeq_op( islower( com ) ? INCLUSIVE_SELECTION : NORMAL_SELECTION )
- }
-
- # backwards index
- # return the offset left from the end of the string of the rightmost
- # instance of ch, if any, in s
-
- local function bindex( s, ch ){
- local n = rindex( s, ch )
- if( n )
- n = length( s ) - n + 1
- return n
- }
-
- ## marks & mark motion
-
- # translate a mark ascii name to a bookmark id
-
- local function vi_mark_id( ch ){
- if( !argcount())
- ch = vi_getc()
-
- prev_mark_id = ch
-
- if( ch ~ /[`']/ )
- return vi_base_mark
- if( ch ~ /[a-zA-Z]/ )
- return vi_base_mark + ord( toupper( ch )) - ord( "@" )
- vi_beep()
- }
-
-
- # record current position into "`" mark
- # called by all motion commands to permit goto previous location,
- # and to mark the range of vi operators
- #
- # context_type: 0 or Null => mark motion starting point
- # 1 => mark non-relative motion starting point
- # 2 => don't mark (for vi_place_mark)
-
- local function mark_context( context_type ){
- if( context_type == DONT_MARK )
- return
-
- if( context_type == MAJOR_MARK )
- create_mark( vi_major_mark ) # , current_line, current_column )
-
- create_mark( vi_base_mark ) #, current_line, current_column )
- }
-
-
- # m command -- places a mark here
-
- function vi_place_mark(){
- operator_disallowed()
- disallow_number()
- record_op()
- create_mark( vi_mark_id(), current_line, current_column )
- }
-
- function vi_goto_mark(){
- local lines = chr( current_key ) == vi_line_mark
- local mark
-
- disallow_number()
- record_op()
- op_type_2b( DONT_MARK )
- mark = vi_mark_id()
-
- if( mark == vi_base_mark )
- swap_marks( vi_major_mark )
- else {
- if( !mark_defined( mark ))
- vi_beep()
- mark_context( MAJOR_MARK )
- goto_mark( mark )
- }
-
- if( lines )
- skip_whitespace()
-
- xeq_op( lines ? LINE_SELECTION : NORMAL_SELECTION )
- }
-
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
- ### ex mode
- #
- # ex_key: prompt the user; call ex_mode if something entered
- #
- # ex_mode: handle non-globable prefix and suffix
- #
- # ex_mode1: called recursively by ex_glob()
- #
- # Bug: this version ignores superflurous stuff after a valid command
-
- function ex_key(){
- local com
-
- operator_disallowed()
- establish_baseline()
-
- com = prompt_history( "EX_MODE", ":" )
- if( com )
- ex_mode( com )
- }
-
- local function ex_mode( command ){
- ex_com = command
- ex_address_range()
-
- ex_mode1()
-
- if( browser_bid )
- browse_printed()
-
- vi_command_mode()
- }
-
- local function ex_mode1( command ){
- local i, n, com
-
- if( command )
- ex_com = command
-
- com = eat_char()
- if( com == "s" && ex_com ~ /^h/ )
- com = com eat_char()
-
- if( com == "s" ){
- ex_sub()
-
- } else if( com == "g" || com == "v" ){
- ex_glob( com )
-
- } else if( com == "w" ){
- if( eat_match( "q" )){
- ex_write()
- ex_quit()
- } else
- ex_write()
-
- } else if( com == "d" ){
- select_range( DEFAULT_ONE )
- vi_yank( AND_DELETE )
-
- } else if( com == "=" ){
- n = ( ex_addresses > 1 ) ? ex_addr2 : ex_addr1
- if( in_glob )
- pbuf( n )
- else
- message( n )
-
- # message( "(%d) addresses: %d, %d", \
- # ex_addresses, \
- # ex_addr1, \
- # ex_addr2 )
-
- } else if( com == "p" || com == "l" || ex_addresses > 11 && com == "" ){
- select_range( DEFAULT_ONE )
- copy_to_scrap()
- scrap_to_browser()
- raise_anchor()
-
- } else if( com == "" && ex_addresses == 1 ){
- vi_goto_line( ex_addr1 )
-
- } else if( com == "r" ){
- ex_read()
-
- } else if( in_glob ){
- message( "can't glob :" com ex_com )
-
- } else if( ex_addresses ){
- message( "addresses are illegal for :" com ex_com )
-
- } else if( com == "e" ){
- ex_edit()
-
- } else if( com == "f" ){
- if(( com = eat_arg()))
- buffer_filename = com
- ex_show_file()
-
- } else if( com == "n" ){
- next_buffer()
- ex_show_file()
-
- # } else if( com == "p" ){
- # prev_buffer()
- # ex_show_file()
-
- } else if( com == "sh" ){
- system()
-
- } else if( com == "!" ){
- if( eat_bang())
- com = current_history_item( "!" )
- else
- com = add_prompt_history( "!", eat_arg())
- system( com )
-
- } else if( com == "x" ){
- write_and_exit()
-
- } else if( com == "q" ){
- ex_quit()
-
- } else
- message( "unrecognized command" )
- }
-
- local function ex_quit( force ){
- force = force || eat_bang()
-
- if( !force && buffers_modified )
- warning( "file has been modified; \"q!\" quits discarding changes" )
- else
- quit( force )
- }
-
- local function ex_write(){
- local force = eat_bang()
- local name = eat_arg()
-
- if( !name )
- name = buffer_filename
-
- if( region_type()){
- write_marked_block( name )
-
- } else if( ex_addresses ){
- select_range()
- write_marked_block( name )
- raise_anchor()
-
- } else
- write_buffer( name )
- }
-
- local function ex_read(){
- # local force = eat_bang()
- local name = eat_arg()
-
- if( !name )
- name = vi_read_name
- if( !name )
- vi_beep( "must supply file name to read" )
- vi_read_name = name
-
- if( ex_addresses > 1 )
- vi_beep( "only 0 or 1 addresses allowed for :r" )
-
- if( ex_addresses )
- current_line = ex_addr1 + 1 # may be 0
- else
- current_line++
-
- goto_bol()
-
- read_file( name )
- }
-
- local function ex_edit( ){
- # local force = eat_bang()
- local name = eat_arg()
-
- if( name ){
- edit_file( name )
- ex_show_file()
- }
- }
-
- local function vi_filter(){
- local com = prompt_history( "!", "!", "", 1 )
-
- if( com )
- filter( com )
- }
-
- function ex_show_file( annotation ){
- local pct = 100
-
- # # faster, but less accurate:
- # if( buffer_size > 0 )
- # pct = 100 * buffer_offset / buffer_size
- if( buffer_last_line > 0 )
- pct = 100 * current_line / buffer_last_line
-
- if( !annotation && and( buffer_flags, BUFFER_MODIFIED ))
- annotation = "[modified]"
-
- message( "\"%s\" %sline %d of %d -- %d%% --", \
- buffer_filename, \
- ( annotation ? annotation " " : "" ), \
- current_line, \
- buffer_last_line, \
- pct )
- }
-
- local function ex_sub(){
- local quote = eat_char()
- local old = search_hist( eat_regex( quote ))
- local new = eat_regex( quote )
- local gp = eat_match( "[gp]+" ) # ":s/foo" is the same as ":s/foo//"
- local pflag, start, stop, count, n = 0
- local sflags = or( or( SEARCH_FWD_REGEX_MAX, SEARCH_BLOCK ), \
- and( search_flags, SEARCH_IGNORE_CASE ))
-
- if( match( "", old ) && RLENGTH == 0 )
- vi_beep( "NULL search pattern length." );
-
- if( gp !~ "p" ){
- search_count = 0x7FFFFFFF;
- if( gp !~ /g/ ){
- sflags = sflags + SEARCH_ONCE_PER_LINE
- }
- select_range( DEFAULT_ONE )
- n = replace( old, new, sflags )
- raise_anchor()
- } else {
- stop = ex_range( DEFAULT_ONE )
- start = current_line
- count = ( gp ~ /g/ ) ? 0x7FFFFFFF : 1
- pflag = ( gp ~ /p/ )
-
- while( start <= stop ){
- goto_pos( start++, 1 )
- drop_anchor( LINE_SELECTION )
- search_count = count
- n += replace( old, new, sflags )
- if( pflag ){
- copy_to_scrap()
- scrap_to_browser()
- }
- raise_anchor()
- }
- }
-
- if( !in_glob )
- message( "%d replacements made", n )
- }
-
- local function ex_glob( gv ){
- local com, quote, regex, n = 0
- local sflags = or( or( SEARCH_FWD_REGEX_MAX, SEARCH_BLOCK ), \
- or( SEARCH_ADVANCE, \
- and( search_flags, SEARCH_IGNORE_CASE )))
-
- if( in_glob )
- vi_beep( "recursive :" gv " is not allowed" )
- in_glob = 1
- gv = ( gv == "v" )
-
- quote = eat_char()
- regex = search_hist( eat_regex( quote ))
-
- if( match( "", regex ) && RLENGTH == 0 )
- vi_beep( "NULL search pattern length." );
-
- com = ex_com # save remainder of glob command
- search_count = 1
-
- select_range()
- save_position()
-
- while( search( regex, sflags )){
-
- restore_position()
- save_position()
-
- ex_addr1 = ex_addr2 = current_line
- ex_addresses = 1
- ex_mode1( com )
-
- if(( n++ % 10 ) == 3 )
- display_update()
-
- if( com !~ /d/ )
- goto_eol()
- }
-
- restore_position( 1 )
-
- if( region_type())
- raise_anchor()
- in_glob = 0
-
- message( "%d lines processed", n )
- }
-
- local function ex_range( defaultOne ){
- local start, stop
-
- if( region_type()){
- stop = current_line
- swap_marks()
- start = current_line
- raise_anchor()
- if( stop < start ){
- start = stop
- stop = current_line
- }
- } else if( ex_addresses ){
- start = ex_addr1
- stop = ex_addr2
- } else if( defaultOne ){
- start = stop = current_line
- } else {
- start = 1
- stop = buffer_last_line - 1
- }
-
- current_line = start
- return stop
- }
-
-
- local function browser_buffer(){
- if( !browser_bid )
- browser_bid = create_buffer( "", "", 1 )
-
- return browser_bid
- }
-
- local function scrap_to_browser(){
- local cur_buf = current_buffer
-
- current_buffer = browser_buffer()
- goto_buffer_bottom()
- insert_scrap()
-
- current_buffer = cur_buf
- }
-
- local browser_keymap = -1
-
- local function browse_printed(){
- local cur_win = current_window
- local cur_buf = current_buffer
- local cur_map = current_keymap
-
- if( browser_keymap == -1 ){
- current_keymap = browser_keymap = create_keymap( empty_keymap )
-
- assign_key( "<Esc>", "process_end" )
- assign_key( "G", "vi_goto" )
- assign_key( "g", "vi_goto 1" )
- assign_key( "<Home>", "vi_goto_bol" )
- assign_key( "<End>", "vi_goto_eol" )
- assign_key( "+", "vi_next_line" )
- assign_key( "-", "vi_prev_line" )
- assign_key( "<Enter>", "vi_next_line" )
- assign_key( "<Keypad-Minus>", "vi_prev_line" )
- assign_key( "<Keypad-+>", "vi_next_line" )
- assign_key( "H", "vi_H" )
- assign_key( "M", "vi_M" )
- assign_key( "L", "vi_L" )
- assign_key( "<Ctrl-PgUp>", "goto_buffer_top" )
- assign_key( "<Ctrl-PgDn>", "goto_buffer_bottom" )
- assign_key( "<PgUp>", "page_up" )
- assign_key( "<PgDn>", "page_down" )
- assign_key( "<Ctrl-B>", "page_up" )
- assign_key( "<Ctrl-F>", "page_down" )
- assign_key( "<Ctrl-D>", "scroll_down_half" )
- assign_key( "<Ctrl-U>", "scroll_up_half" )
- assign_key( "<Ctrl-E>", "scroll_down_1" )
- assign_key( "<Ctrl-Y>", "scroll_up_1" )
- }
-
- current_keymap = browser_keymap
-
- current_window = create_window()
- current_buffer = browser_buffer()
- attach_window_buffer( current_window, current_buffer )
- window_name = "Command Output Listing"
- message( "Use motion keys to browse, ESC to exit" )
-
- process_begin()
-
- message( "" )
- delete_buffer( current_buffer )
- delete_window( current_window )
- current_buffer = cur_buf
- current_window = cur_win
- current_keymap = cur_map
-
- browser_bid = 0
-
- }
-
- local function pbuf( s ){
- local cur_buf = current_buffer
-
- current_buffer = browser_buffer()
- insert_string( s "\n" )
-
- current_buffer = cur_buf
- }
-
-
- # select a region based on starting and ending addresses
-
- local function select_range( defaultOne ){
- if( ex_addresses ){
- current_line = ex_addr2
- current_column = 1
- drop_anchor( LINE_SELECTION )
- if( ex_addresses > 1 )
- current_line = ex_addr1
- } else if( defaultOne )
- drop_anchor( LINE_SELECTION )
- else
- current_line = current_column = 1
- }
-
- # parse a range address expression; result is 0, 1 or 2 numbers
- #
- # term:
- # .
- # $
- # 'a
- # /.../
- # ?...?
- # addr:
- # term
- # term + num
- # term - num
- # + num # . + num
- # - num # . - num
- # term + # term + 1
- # term - # term - 1
- # num
- # range:
- # /* empty */ # 1,$
- # addr
- # addr , addr
- # addr ; addr
- # , # 1,$
- # ; # .,$
- #
- local function ex_address(){
- local len1, len = length( ex_com )
- local num, patt, mark, op
-
- # get stand-alone term, if any:
-
- if( eat_match( "/" )){
- vi_search( eat_regex( "/" ), SEARCH_FORWARD )
- ex_addr2 = current_line
-
- } else if( eat_match( "\\?" )){
- vi_search( eat_regex( "?" ), SEARCH_BACKWARD )
- ex_addr2 = current_line
-
- } else if( eat_match( "\\." )){
- ex_addr2 = current_line
-
- } else if( eat_match( "\\$" )){
- ex_addr2 = buffer_last_line - 1
-
- } else if(( patt = eat_match( "'." ))){
- mark = vi_mark_id( substr( patt, 2 ))
- if( !mark_defined( mark ))
- bad_addr()
- ex_addr2 = mark_line( mark )
-
- } else
- ex_addr2 = current_line # missing -- set default
-
- len1 = len - length( ex_com )
-
- # get operator, if any:
-
- op = eat_match( "[+\\-]" )
-
- line_search = !!op # signal to vi_search_key()
-
- # get number, if any:
-
- if(( num = eat_match( "[0-9]+" ))){
- if( len1 && op == "" )
- bad_addr()
- num = 0 + num
- } else
- num = 1
-
- # compute final value:
-
- if( op == "+" )
- ex_addr2 = ex_addr2 + num
- else if( op == "-" )
- ex_addr2 = ex_addr2 - num
- else if( !len1 ) # if no op and no stand-alone term
- ex_addr2 = num
-
- # update address count, if any:
-
- if( len != length( ex_com ))
- ex_addresses ++
-
- return ex_addr2
- }
-
- local function ex_address_range(){
- local ch
-
- ex_addresses = 0
- mark_context()
- ex_addr1 = ex_address()
-
- if( ex_addresses ){
- if( ex_com ~ /^;/ ){
- vi_goto_line( ex_addr1 )
- goto_bol()
- }
- if( eat_match( "[,;]" )){
- ex_addr2 = ex_address()
- if( ex_addresses != 2 )
- bad_addr()
- }
-
- } else if( eat_match( "[,%]" )){
- ex_addr1 = 1
- ex_addr2 = buffer_last_line - 1
- ex_addresses = 2
-
- } else if( eat_match( ";" )){
- ex_addr1 = current_line
- ex_addr2 = buffer_last_line - 1
- ex_addresses = 2
-
- } else {
- ex_addr1 = ex_addr2 = current_line
- }
-
- if( ex_addresses > 1 && ex_addr1 > ex_addr2 )
- bad_addr()
-
- goto_mark( vi_base_mark )
- }
-
- local function bad_addr(){
- goto_mark( vi_base_mark ) # restore initial position
- vi_beep( "Ill-formed address" )
- }
-
- ## address and ex mode parser helpers
- #
- # eat_... => if match then return the matched string and advance ex_com;
- # else return null without advancing ex_com.
-
- local function eat_match( patt ){
- local r = ""
-
- if( match( ex_com, "^" patt )){
- r = substr( ex_com, 1, RLENGTH )
- ex_com = substr( ex_com, RLENGTH + 1 )
- }
- return r
- }
-
- local function eat_space(){
- return eat_match( "[ \t]*" )
- }
-
- local function eat_bang(){
- return eat_match( "!" )
- }
-
- local function eat_arg(){
- eat_space()
- return eat_match( "[^;]+" )
- }
-
- local function eat_char(){
- local ch = substr( ex_com, 1, 1 )
- ex_com = substr( ex_com, 2 )
- return ch
- }
-
- # eat a regular expression, with <sep> as the separator.
- #
- # syntax is sep regex sep
- # or sep regex EOL
- #
- # sep is "/" or "?"
- #
- # Leading separator should already have been removed.
- # We don't use eat_match to avoid the slower anchored search.
- # This is a good place to implement nomagic and other regex
- # transformations.
- #
- local function eat_regex( sep ){
- local patt, regex, len
-
- # closing seperator may be prefixed by an even number of backslashes;
- # an odd number of backslashes quote the seperator, requiring it to
- # be included in the regex.
-
- patt = "[^\\\\](\\\\\\\\)*"
- if( sep ~ /[|\]^$*+(){}.?\\]/ ) # regex seperators must be quoted
- sep = "\\" sep
-
- # split the input into a regex LHS and a remainder RHS, discarding
- # the closing seperator; two matches because first may not be longest
-
- if( match( ex_com, "^" sep ) || match( ex_com, patt sep )){
- len = RSTART + RLENGTH - 1 # index of closing seperator
- regex = substr( ex_com, 1, len - 1 )
- ex_com = substr( ex_com, len + 1 )
- } else {
- regex = ex_com
- ex_com = ""
- }
-
- # Now remove quotes from quoted seperators. By definition, they must
- # have an odd number of preceeding backslashes, one of which must be
- # removed. However, regex chars need to retain the quoting.
-
- if( length( sep ) == 1 )
- gsub( "\\" sep, sep, regex )
-
- return regex
- }
-
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
- ### regex searches
- #
- # vi_search searches forwards or backwards for 1 pattern
- # vi_beep()s if the pattern is not found.
- # vi_search_key prompts for input, and otherwise handles the
- # "/" and "?" commands
- # vi_search_again handles the "n", "N", and Alt-F5 and Alt-F6 commands.
- #
- # search_hist() recalls or remembers previous search pattern
- #
-
- function vi_search_key( key ){
- local patt, addr
-
- disallow_number()
- op_type_2b( DONT_MARK )
-
- patt = prompt_history( "SEARCH", key, "", 1 )
-
- if( patt ){
- record_op( ENTER_KEY )
-
- vi_search_dir = ( key == "/" ? SEARCH_FORWARD : SEARCH_BACKWARD )
- mark_context( MAJOR_MARK ) # mark context for motion
-
- ex_com = key patt
- addr = ex_address() # parse command, call vi_search() as needed
-
- # execute op, if any, in line or normal mode
-
- if( line_search ){
- vi_goto_line( addr )
- xeq_op( LINE_SELECTION )
- } else
- xeq_op()
-
- } else
- op_flush()
- }
-
- local function search_hist( patt ){
-
- if( patt )
- add_prompt_history( SEARCH_HIST, patt )
- else {
- patt = current_history_item( SEARCH_HIST )
- if( !patt )
- vi_beep( "Missing previous pattern" )
- }
-
- return patt
- }
-
-
- local function vi_search( pattern, dir ){
- pattern = search_hist( pattern )
- if( !search( pattern, or( vi_search_flags, dir )))
- vi_beep()
- }
-
- # search again is called by 4 different keys, with 4 different meanings:
- #
- # n search again, same direction as originally
- # N search again, opposite direction as originally
- # Alt-F5 search again, backwards
- # Alt-F6 search again, forwards
- #
- function vi_search_again( key ){
- local dir
-
- disallow_number()
- op_type_2b( MAJOR_MARK )
-
- # figure out what direction we're going...
-
- dir = ( argcount() \
- ? (( key == "?" ) \
- ? SEARCH_BACKWARD \
- : SEARCH_FORWARD ) \
- : (( chr( and( 255, current_key )) == "N" ) \
- ? (( vi_search_dir == SEARCH_FORWARD ) \
- ? SEARCH_BACKWARD \
- : SEARCH_FORWARD ) \
- : \
- vi_search_dir ))
-
- message( "%s%s", ( dir == SEARCH_FORWARD ? "/" : "?" ), search_hist())
-
- # execute search operator:
-
- vi_search( "", dir )
- xeq_op()
- }
-
-
-
-
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
- # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-
- ### create the VI keymaps if they have not already been
- #
- local function create_vi_keymaps(){
-
- # Enable the keymap. Subsequent mods to the keymap will persist
- # through the end of the session.
- # Only one-time initialization should follow this point.
-
- if( vi_command_keymap >= 0 ){
- current_keymap = vi_command_keymap
- return
- }
-
- current_keymap =
- vi_command_keymap =
- create_keymap( empty_keymap )
-
- assign_key( "<Esc>", "vi_beep" )
-
- # ex-mode commands
-
- assign_key( ":", "ex_key" )
-
- # searches
-
- assign_key( "?", "vi_search_key ?" )
- assign_key( "/", "vi_search_key /" )
- assign_key( "n", "vi_search_again" )
- assign_key( "N", "vi_search_again" )
-
- # command count prefixes ("0" command handled by vi_digit)
-
- assign_key( "0", "vi_digit" )
- assign_key( "1", "vi_digit" )
- assign_key( "2", "vi_digit" )
- assign_key( "3", "vi_digit" )
- assign_key( "4", "vi_digit" )
- assign_key( "5", "vi_digit" )
- assign_key( "6", "vi_digit" )
- assign_key( "7", "vi_digit" )
- assign_key( "8", "vi_digit" )
- assign_key( "9", "vi_digit" )
-
- # simple motions
-
- assign_key( "h", "vi_left" )
- assign_key( "<Left>", "vi_left" )
- assign_key( "j", "vi_down" )
- assign_key( "<Down>", "vi_down" )
- assign_key( "<Ctrl-N>", "vi_down" )
- assign_key( "k", "vi_up" )
- assign_key( "<Up>", "vi_up" )
- assign_key( "<Ctrl-P>", "vi_up" )
- assign_key( "l", "vi_right" )
- assign_key( "<Right>", "vi_right" )
- assign_key( "G", "vi_goto" )
- assign_key( "g", "vi_goto 1" )
- assign_key( "|", "vi_goto_column" )
-
- assign_key( "<Home>", "vi_goto_bol" )
- assign_key( "^", "vi_skip_whitespace" )
- assign_key( "$", "vi_goto_eol" )
- assign_key( "<End>", "vi_goto_eol" )
- assign_key( "+", "vi_next_line" )
- assign_key( "-", "vi_prev_line" )
- assign_key( "<Enter>", "vi_next_line" )
- assign_key( "%", "vi_goto_matching" )
- assign_key( "<Ctrl-Right>", "vi_W" )
- assign_key( "<Ctrl-Left>", "vi_B" )
-
- assign_key( "<Keypad-Minus>", "vi_prev_line" )
- assign_key( "<Keypad-+>", "vi_next_line" )
-
- assign_key( "H", "vi_H" )
- assign_key( "M", "vi_M" )
- assign_key( "L", "vi_L" )
- assign_key( "<Ctrl-PgUp>", "goto_buffer_top" ) # extension!
- assign_key( "<Ctrl-PgDn>", "goto_buffer_bottom" ) # extension!
-
- # need work to be truly integrated with VI:
-
- assign_key( " ", "vi_space" )
- assign_key( "#8", "vi_bksp" ) # Ctrl-H or Backspace
- assign_key( "#9", "vi_tab" ) # Ctrl-I or Tab
- assign_key( "<Shift-Tab>", "vi_back_tab" )
- assign_key( "<Alt-Tab>", "vi_back_tab" )
-
- # need work to be truly integrated with VI:
-
- # assign_key( "<Keypad 4>", "left" )
- # assign_key( "<Keypad 6>", "right" )
-
- # word motions and other structured motions:
-
- assign_key( "w", "vi_w" )
- assign_key( "b", "vi_b" )
- assign_key( "e", "vi_e" )
- assign_key( "W", "vi_W" )
- assign_key( "B", "vi_B" )
- assign_key( "E", "vi_E" )
- assign_key( "(", "vi_prev_sent" )
- assign_key( ")", "vi_next_sent" )
- assign_key( "{", "vi_prev_para" )
- assign_key( "}", "vi_next_para" )
- assign_key( "[[", "vi_prev_sect" )
- assign_key( "]]", "vi_next_sect" )
-
- # "find" motions:
-
- assign_key( "f", "vi_find" )
- assign_key( "F", "vi_find" )
- assign_key( "t", "vi_find" )
- assign_key( "T", "vi_find" )
- assign_key( ";", "vi_find_repeat" )
- assign_key( ",", "vi_find_reverse" )
-
- # mark placement & motion:
-
- assign_key( "m", "vi_place_mark" )
- assign_key( "'", "vi_goto_mark" )
- assign_key( "`", "vi_goto_mark" )
-
- # These window "motions" are known or believed not to be motions in
- # the VI sense. However they probably should clear pending operators
- # (to avoid confusion, eg., on "dz-").
- # They also should disallow_number().
-
- assign_key( "<PgUp>", "page_up" ) # not a motion
- assign_key( "<PgDn>", "page_down" ) # not a motion
- assign_key( "<Ctrl-B>", "page_up" ) # not a motion
- assign_key( "<Ctrl-F>", "page_down" ) # not a motion
- assign_key( "<Ctrl-D>", "scroll_down_half" ) # not a motion
- assign_key( "<Ctrl-U>", "scroll_up_half" ) # not a motion
- assign_key( "<Ctrl-E>", "scroll_down_1" ) # not a motion
- assign_key( "<Ctrl-Y>", "scroll_up_1" ) # not a motion
- assign_key( "<Ctrl-Home>", "goto_window_top" )
- assign_key( "<Ctrl-End>", "goto_window_bottom" )
-
- assign_key( "z<Enter>", "scroll_window_top" )
- assign_key( "z.", "scroll_window_middle" )
- assign_key( "z-", "scroll_window_bottom" )
-
- # misc. edits
-
- assign_key( "i", "vi_i" )
- assign_key( "a", "vi_a" )
- assign_key( "A", "vi_A" )
- assign_key( "I", "vi_I" )
- assign_key( "o", "vi_o" )
- assign_key( "O", "vi_O" )
-
- assign_key( "r", "vi_r" )
- assign_key( "R", "vi_R" )
- assign_key( "s", "vi_s" )
- assign_key( "S", "vi_S" )
-
- assign_key( "C", "vi_C" )
- assign_key( "D", "vi_D" )
- assign_key( "J", "vi_J" )
- assign_key( "x", "vi_x" )
- assign_key( "X", "vi_X" )
-
- assign_key( "~", "vi_tilde" )
-
- # editing operators:
-
- assign_key( "d", "vi_operator" )
- assign_key( "c", "vi_operator" )
- assign_key( "\\<", "vi_operator" )
- assign_key( ">", "vi_operator" )
- assign_key( "!", "vi_operator" )
- assign_key( "y", "vi_operator" )
-
-
- # Yank, Put, Undo, Repeat, Retrieve:
-
- assign_key( "\"", "vi_bufid_key" )
- assign_key( "Y", "vi_Y" )
- assign_key( "p", "vi_p" )
- assign_key( "P", "vi_P" )
-
- assign_key( ".", "vi_again" )
- assign_key( "u", "vi_undo" )
- assign_key( "U", "vi_undo_line" )
-
-
- # getting out & misc:
-
- assign_key( "<Alt-Q>", "quit" )
- assign_key( "ZZ", "write_and_exit" )
-
- assign_key( "<Ctrl-L>", "scroll_left_1" )
- assign_key( "<Ctrl-R>", "scroll_right_1" ) # inexact but appropriate substitution
- assign_key( "<Ctrl-G>", "ex_show_file" )
-
- # extensions in common with native keymap:
-
- assign_key( "<Ins>", "vi_P" )
- assign_key( "<Del>", "vi_yank 1" )
- assign_key( "<Alt-Minus>", "delete_buffer_key" )
-
- assign_key( "<Ctrl-A>", "optional_function display_ascii_table" )
- assign_key( "<Ctrl-Z>", "system" )
-
- # Function key combinations & other useful native bindings:
-
- assign_key( "<F1>", "prev_window" )
- assign_key( "<F2>", "next_window" )
- assign_key( "<F3>", "prev_buffer_key" )
- assign_key( "<F4>", "next_buffer_key" )
- assign_key( "<F5>", "vi_search_key ?" )
- assign_key( "<F6>", "vi_search_key /" )
- assign_key( "<F7>", "record_key" )
- assign_key( "<F8>", "playback" )
- assign_key( "<F9>", "system_key" )
- assign_key( "<F10>", "invoke_function" )
-
- assign_key( "<Alt-F1>", "split_window_horizontal" )
- assign_key( "<Alt-F2>", "split_window_vertical" )
- assign_key( "<Alt-F3>", "make_window" )
- assign_key( "<Alt-F4>", "delete_tiled_window" )
- assign_key( "<Alt-F5>", "vi_search_again ?" )
- assign_key( "<Alt-F6>", "vi_search_again /" )
- assign_key( "<Alt-F7>", "learn_key" )
- # assign_key( "<Alt-F8>", )
- # assign_key( "<Alt-F9>", )
- assign_key( "<Alt-F10>", "compile_buffer" )
-
- assign_key( "<Shift-F1>", "smaller_window" )
- assign_key( "<Shift-F2>", "larger_window" )
- assign_key( "<Shift-F3>", "organize_windows" )
- assign_key( "<Shift-F4>", "organize_buffers" )
- # assign_key( "<Shift-F5>", )
- # assign_key( "<Shift-F6>", )
- assign_key( "<Shift-F7>", "display_errors" )
- assign_key( "<Shift-F8>", "goto_next_error" )
- # assign_key( "<Shift-F9>", )
- # assign_key( "<Shift-F10>", )
-
- # assign_key( "<Ctrl-F1>", )
- # assign_key( "<Ctrl-F2>", )
- # assign_key( "<Ctrl-F3>", )
- # assign_key( "<Ctrl-F4>", )
- # assign_key( "<Ctrl-F5>", )
- # assign_key( "<Ctrl-F6>", )
- # assign_key( "<Ctrl-F7>", )
- # assign_key( "<Ctrl-F8>", )
- # assign_key( "<Ctrl-F9>", )
- # assign_key( "<Ctrl-F10>", )
-
- assign_key( "<Alt-A>", "set_exclusive_mark" )
- assign_key( "<Alt-B>", "buffer_list" )
- assign_key( "<Alt-C>", "copy_to_scrap_key" )
- assign_key( "<Alt-D>", "native_delete" )
- assign_key( "<Alt-E>", "edit_file_key" )
- assign_key( "<Alt-F>", "display_filename" )
- assign_key( "<Alt-G>", "goto_line_or_mark" )
- assign_key( "<Alt-H>", "help" )
- assign_key( "<Alt-I>", "toggle_insert_mode" )
- assign_key( "<Alt-J>", "vi_J" )
- assign_key( "<Alt-K>", "delete_to_eol" )
- assign_key( "<Alt-L>", "set_line_mark" )
- assign_key( "<Alt-M>", "mark_matching" )
- assign_key( "<Alt-N>", "next_buffer_key" )
- assign_key( "<Alt-O>", "change_output_name" )
- assign_key( "<Alt-P>", "wrap_paragraph" )
- assign_key( "<Alt-Q>", "done" )
- assign_key( "<Alt-R>", "read_file_key" )
- assign_key( "<Alt-S>", "search_forward" )
- assign_key( "<Alt-T>", "replace_forward" )
- assign_key( "<Alt-U>", "undo" )
- assign_key( "<Alt-V>", "print_version" )
- assign_key( "<Alt-W>", "write_block_key" )
- assign_key( "<Alt-X>", "done" )
- assign_key( "<Alt-Y>", "redo" )
- assign_key( "<Alt-Z>", "system" )
-
- # Alt-digit codes:
-
- assign_key( "<Alt-1>", "place_bookmark 1" )
- assign_key( "<Alt-2>", "place_bookmark 2" )
- assign_key( "<Alt-3>", "place_bookmark 3" )
- assign_key( "<Alt-4>", "place_bookmark 4" )
- assign_key( "<Alt-5>", "place_bookmark 5" )
- assign_key( "<Alt-6>", "place_bookmark 6" )
- assign_key( "<Alt-7>", "place_bookmark 7" )
- assign_key( "<Alt-8>", "place_bookmark 8" )
- assign_key( "<Alt-9>", "place_bookmark 9" )
- assign_key( "<Alt-0>", "place_bookmark 10" )
-
- assign_mouse_buttons()
-
- # insert-mode keymap
-
- vi_insert_keymap = current_keymap = create_keymap( ascii_keymap )
-
- assign_key( "<Esc>", "process_end" )
- assign_key( "#27", "process_end" ) # Esc or Ctrl-]
- assign_key( "<Ctrl-C>", "vi_beep" )
- assign_key( "<Ctrl-@>", "vi_reinsert" )
- assign_key( "#10", "vi_ai_nl" ) # Ctrl-J or Ctrl-Enter
- assign_key( "#13", "vi_ai_cr" ) # Ctrl-M or Enter
- assign_key( "<Bksp>", "vi_insert_bs" )
- assign_key( "<Ctrl-H>", "vi_insert_bs" )
- assign_key( "<Ctrl-W>", "vi_insert_dB" )
- assign_key( "<Ctrl-U>", "vi_insert_cancel" )
- assign_key( "<Ctrl-V>", "vi_insert_quoted" )
- assign_key( "<Ctrl-D>", "vi_insert_unindent" )
- assign_key( "<Ctrl-T>", "goto_next_tab" )
- assign_key( "<F1>", "expand_template" )
- assign_key( "<F2>", "expand_template" )
- }
-