Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Import Elvis 2.2_1 (written by Steve Kirkendall)

  • Loading branch information...
commit 2fe6e177ffa64c254a5f795915c2bc3f85d8dd85 1 parent 9f1c6f0
@mbert authored
Showing with 12,161 additions and 1,371 deletions.
  1. +0 −39 Announce-2.2_0
  2. +321 −0 Announce-2.2_1
  3. +12 −9 Makefile.in
  4. +355 −29 README.html
  5. +22 −32 autocmd.c
  6. +916 −22 buffer.c
  7. +6 −1 buffer.h
  8. +14 −6 calc.c
  9. +2 −5 color.c
  10. +9 −0 configure
  11. +69 −0 data/elvgdb.ini
  12. +27 −3 data/elvis.ali
  13. +2 −1  data/elvis.arf
  14. +2 −1  data/elvis.awf
  15. +1 −1  data/elvis.brf
  16. +9 −6 data/elvis.bwf
  17. +2 −2 data/elvis.clr
  18. +20 −20 data/elvis.ini
  19. +41 −9 data/elvis.syn
  20. +38 −0 data/icons/vi.xpm
  21. +1 −1  data/scripts/dict.ex
  22. +184 −0 data/scripts/gdb.ex
  23. +8 −2 data/scripts/{augz.ex → gzip.ex}
  24. +9 −0 data/scripts/herefile.ex
  25. +92 −67 data/scripts/html.ex
  26. +250 −1 data/scripts/life.ex
  27. +1 −0  data/scripts/likevim.ex
  28. +11 −0 data/scripts/mail.ex
  29. +0 −15 data/scripts/mailto.ex
  30. +53 −0 data/scripts/note.ex
  31. +5 −3 data/scripts/sfb.ex
  32. +10 −0 data/scripts/shuffle.ex
  33. +16 −14 data/scripts/since.ex
  34. +1 −1  data/scripts/xbuf.ex
  35. +6 −3 data/stubs/ansistub.c
  36. +2 −6 digraph.c
  37. +63 −7 dmmarkup.c
  38. +2 −2 dmnormal.c
  39. +622 −26 doc/bugs.txt
  40. +1 −1  doc/ctags.man
  41. +352 −0 doc/elvgdb.man
  42. +5 −4 doc/elvis.html
  43. +19 −20 doc/elvis.man
  44. +2 −2 doc/elviscut.html
  45. +17 −1 doc/elvisdm.html
  46. +160 −92 doc/elvisex.html
  47. +3,104 −0 doc/elvisex.html.orig
  48. +6 −5 doc/elvisexp.html
  49. +89 −60 doc/elvisgui.html
  50. +1 −1  doc/elvisinp.html
  51. +1 −1  doc/elvismsg.html
  52. +1 −1  doc/elvisnet.html
  53. +332 −87 doc/elvisopt.html
  54. +1 −1  doc/elvisos.html
  55. +1 −1  doc/elvisqr.html
  56. +2 −2 doc/elvisre.html
  57. +8 −8 doc/elvisses.html
  58. +2 −2 doc/elvistag.html
  59. +271 −11 doc/elvistip.html
  60. +2,069 −0 doc/elvistip.html.orig
  61. +1 −1  doc/elvisvi.html
  62. +1 −1  doc/fmt.man
  63. +19 −9 doc/howto.html
  64. +1 −1  doc/ref.man
  65. +6 −2 draw.c
  66. +1,064 −0 elvgdb.c
  67. +1 −0  elvis.h
  68. +231 −138 ex.c
  69. +2 −2 ex.h
  70. +88 −25 exaction.c
  71. +37 −40 exconfig.c
  72. +14 −19 exedit.c
  73. +4 −4 exmake.c
  74. +3 −3 fold.c
  75. +15 −4 gui.c
  76. +78 −59 guitcap.c
  77. +66 −66 guiwin32/guiwin.c
  78. +75 −59 guix11/guix11.c
  79. +2 −1  guix11/guix11.h
  80. +15 −2 guix11/xdialog.c
  81. +2 −1  guix11/xdialog.h
  82. +54 −5 guix11/xevent.c
  83. +82 −11 guix11/xtool.c
  84. +2 −1  http.c
  85. +2 −2 input.c
  86. +13 −3 io.c
  87. +24 −14 main.c
  88. +5 −4 makos2.cmd
  89. +26 −21 map.c
  90. +5 −1 message.c
  91. +3 −1 move.c
  92. +5 −6 operator.c
  93. +10 −1 optglob.c
  94. +8 −4 optglob.h
  95. +92 −10 options.c
  96. +2 −1  osmsdos/osconfig.h
  97. +49 −22 osos2/Makefile.os2
  98. +121 −27 osos2/Makefile.os2,v
  99. +3 −2 osos2/config-no-tcp.h
  100. +3 −2 osos2/config-with-tcp.h
  101. +83 −62 osos2/guivio.c
  102. +0 −14 osos2/guivio.h
  103. +7 −4 osos2/osblock.c
  104. +8 −7 osos2/osdir.c
  105. +12 −4 osos2/osnet.c
  106. +8 −5 osos2/osprg.c
  107. +8 −5 osos2/ostext.c
  108. +2 −2 osunix/osnet.c
  109. +3 −2 oswin32/osconfig.h
  110. +3 −2 oswin32/tcaphelp.c
  111. +16 −15 region.c
  112. +75 −4 search.c
  113. +7 −17 spell.c
  114. +2 −2 state.c
  115. +5 −5 tinytcap.c
  116. +3 −2 url.c
  117. +1 −1  version.h
  118. +23 −7 vi.c
  119. +4 −1 vicmd.c
  120. +9 −1 window.c
View
39 Announce-2.2_0
@@ -1,39 +0,0 @@
-As of October 20, Elvis 2.2 is officially released.
-
-To learn about elvis, or download (source, Win32 binaries, or MS-DOS
-binaries) go to...
-
- ftp://ftp.cs.pdx.edu/pub/elvis/README.html
-
-It's been a full four years since the version 2.1.4 was released so you
-should expect a lot of new features. Here's a brief summary:
-
-* Elvis 2.2 is pretty
- o The :color command has been greatly improved.
- o Can use Xft for antialiased text (x11 only).
- o You can use background images. (x11 and windows only)
- o You can load your own elvis icon. (x11 and windows only)
- o Themes are supported. ":theme sand" is included. Other themes are
- available via ":e theme:". (x11 and windows only)
- o Good default colors are provided for all user interfaces.
- o The Windows interface can use X11 color names.
-
-* Elvis 2.2 has many of Vim's feaures
- o :autocmd
- o Many g commands.
- o Name completion. Filenames, commands, options, etc.
- o <key> notation in :map commands.
- o You can load aliases and maps to emulate vim better with ":ru likevim".
-
-* Other stuff
- o Built-in spell checker. Context sensitive, and can suggest corrections.
- o Folding. Lets you hide parts of your text without deleting it.
- o Region highlighting.
- o User-definable URL protocols.
-
-* Still has the best features of 2.1
- o "hex" display mode for editing binary files.
- o "html", "man", and "tex" display modes, for previewing text.
- o Online manual is written in HTML, and viewable with the "html" display
- mode. Look nice, and has many convenient links.
-
View
321 Announce-2.2_1
@@ -0,0 +1,321 @@
+I almost have version 2.1.1 ready. I'm probably about 4 weekends away.
+You can download a copy of the source code from...
+
+ ftp://ftp.cs.pdx.edu/pub/elvis/unreleased/almost-2.2_1.tar.gz
+
+
+The following bugs have been fixed:
+
+ :andale was using Luxi Mono fonts
+ The :andale alias (used in the "x11" user interface) was
+ actually using Luxi Mono fonts instead of Andale fonts.
+
+ filenamerules broke newline handling
+ When I implemented the filenamerules option in 2.2.0, I
+ accidentally broke the way it parses newlines. This is important
+ if you remove the spaces keyword from filenamerules, and then do
+ something like ":n `grep foo *.txt`" to sets the args list to
+ all files containing "foo".
+
+ HTTP User-agent: header line
+ When sending HTTP requests, Elvis should send a User-agent:
+ header line. Some web sites demand this.
+
+ Default button names
+ In the "html" display mode, the <input type=submit> and <input
+ type=reset> tags should have the default values "Submit" and
+ "Reset" respectively. In 2.2.0, they have no default.
+
+ <hr/> shows ------------>
+ The "html" display mode had trouble with tags that end with
+ "/>". Elvis would display the > on the screen instead of hiding
+ it.
+
+ <Esc>
+ The <Esc> key should beep when pressed in visual command mode.
+
+ Delayed screen updates in "x11" user interface
+ When a map times out, Elvis wasn't updating the screens
+ immediately in the "x11" user interface, which made it hard to
+ detect that the map had indeed timed out.
+
+ "d)" could crash
+ In a file full of blank lines, "d)" caused 2.2.0 to dump core.
+
+ :put from a cut buffer
+ The :put command wasn't accepting a cut buffer name argument.
+
+ :dict didn't handle single words
+ The :dict alias (after ":load dict") didn't handle single-word
+ queries correctly.
+
+ The directory editor's links were relative to the wrong directory.
+ If you used ":e dirname" to edit the directory "dirname", then
+ the links in the generated HTML weren't interpreted as being
+ relative to "dirname". They were treated as being relative to
+ the current directory.
+
+ "x11" converts <b> to ^K0062.
+ The "x11" user interface is too aggressive when trying to
+ convert key names from angle-bracket notation to raw characters.
+ If a map contains an HTML tag such as <b>, and the tag name
+ happens to match the name of a key such as the "b" key, then
+ Elvis was trying to convert that keystroke into a raw control
+ sequence.
+
+ ":normal cwFOO^[" didn't work
+ The c operator was implemented in a way that didn't work in the
+ :normal command.
+
+ ".IP \(bu 4" had too large of an indent.
+ This is apparently due to the fact that "4" has no explicit
+ scaling suffix, and .IP was using the wrong default scaling
+ factor.
+
+ Hard to enter ^ in WinElvis on a Norwegian keyboard
+ WinElvis has always had a hard time with "dead keys", but now
+ I'm hopeful that it should work. The ^ key works in Norway now,
+ at least.
+
+ ":e +cmd file" didn't work
+ For the :e command and a few others, the "+" flag could only
+ handle a line number parameter, not a full ex command line.
+
+ Typos in manual.
+ Many found and fixed. Still many more to be found, I'm sure.
+
+ :chregion always changes the comment
+ The :chregion shouldn't change the comment of an existing region
+ unless you give a new comment explicitly, or the old comment was
+ merely the old font name.
+
+ ":set show=spell" doesn't work very well.
+ You need to load the whole dictionary to get good suggestions
+ from the spell checker. In 2.2.0 you had to turn on the
+ "spellautoload" option, but in 2.2.1 that option is on by
+ default.
+
+ :map doesn't list all user-defined maps.
+ 2.2.0 assumed that any map tied to a symbolic key was defined by
+ the system, so it wouldn't list it unless you said ":map all".
+ This means you couldn't see actions mapped to function keys.
+ 2.2.1 is smarter about this -- it adds a flag to indicate
+ whether the map was added by the user or created automatically
+ by the GUI.
+
+ Command names were truncated in error messages.
+ When displaying a "bad command name" error message, 2.2.0 would
+ truncate the name at the first character that prevented it from
+ being recognized as a command. 2.2.1 displays the full name of
+ the bad command, exactly as you typed it.
+
+ :man doesn't display backslashes correctly
+ The :man alias didn't handle backslashes very well, so pages
+ which use a lot of backslashes such as ":man groff_man" looked
+ bad.
+
+ :%unr doesn't always remove all regions.
+ This mostly occured when running autocmds. It also affected the
+ :chregion command.
+
+ :%j only joined two lines
+ The command ":1,%j" joins all lines but ":%j" only joined two.
+
+ elvis.ini maps too much
+ The default "elvis.ini" file contained maps without the nosave
+ flag, so if you ran :mkexrc in an xterm, your ~/.elvisrc file
+ would contain maps that are present in all user interfaces and
+ for all termcap terminal types.
+
+ :mkexrc can lose GUI-specific options
+ The :mkexrc command only saved GUI-specific options for the
+ current GUI. This means that running :mkexrc in the "termcap"
+ interface could clobber your default font for the "x11"
+ interface. 2.2.1 gets around this by storing all GUI-specific
+ options, even those for other GUIs or unknown GUIs, just so it
+ can save them in the ~/.elvisrc file.
+
+ <li><p> looks ugly
+ Many HTML documents use this sequence of tags to generate lists
+ that have a bit of vertical whitespace between items. But 2.2.0
+ was drawing the list item marker (bullet or number) on the blank
+ line, instead of the line where the paragraph's text starts.
+ 2.2.1 treats this as a special case -- it ignores the <p> in
+ this context.
+
+ security=safer is too strict
+ The "security=safer" setting didn't allow some command that it
+ should have allowed. This prevented some harmless and useful
+ commands such as "elvis -client foo" from working. To get this
+ working right, I had to overhaul the behavior of
+ "security=safer". It is no longer a more lenient superset of
+ "security=restricted". See ":help set security" for details.
+
+ One consequence of this is that the "-S" flag now sets
+ security=restricted.
+
+ :wq didn't work when security=safer or security=restricted.
+ The manual said it should. The new version of security=safer
+ doesn't allow any writing, but you can now :wq when
+ security=restricted.
+
+ The "ax" text object didn't support tag names with hyphens
+ I've extended it to allow single hyphens but not double hyphens
+ (since double hyphens mark comments). It also allows colons, for
+ namespace control.
+
+ dirperm(".") returns readonly
+ The dirperm() function didn't recognize directories correctly.
+ This was a bug in the way the "dir:" pseudo-protocol was
+ implemented.
+
+ hlobject didn't allow commas
+ An increasing number of options in elvis store multiple values
+ in comma-delimited lists. The "hlobject" option can store
+ multiple values, but required them to be either crammed together
+ or delimited by spaces. Now it supports commas.
+
+ rcssince didn't work
+ The rcssince alias (part of ":load since") is supposed to be
+ executed when a buffer is loaded, but it used some commands
+ which are illegal during initialization. Most of the commands
+ that are illegal during initialization are only illegal because
+ they're useless until the first file is loaded into a buffer.
+ The rcssince alias was actually running after the file was
+ loaded, so it should be allowed, but Elvis had a rather weak
+ idea of when "initialization" ends.
+
+ :suspend didn't work
+ It wasn't in Elvis' internal command list correctly. The :stop
+ equivalent has always worked though.
+
+ Backslashes aren't handled right in "simpler syntax"
+ If a "simpler syntax" expression started with \( or \$ then
+ Elvis should convert that to a literal ( or $ character.
+ Instead, 2.2.0 was leaving it as a literal \ followed by an
+ parenthesized subexpression, or $ variable substitution. (This
+ arose from trying to make an initial \\ remain unchanged so
+ Windows users could five UNC names such as \\machine\dir\file.)
+
+ AliasLeave events
+ At the end of an alias, 2.2.0 generated an AliasEnter event when
+ it should have generated an AliasLeave event.
+
+ :eval does not compute
+ The :eval command could get confused if the command that it runs
+ needs to evaluate an expression. This was because a static
+ buffer is used to return the results of evaluations, and :eval
+ didn't copy the result into a local buffer before trying to
+ execute it.
+
+ Trouble with gzipped files
+ The ":load gzip" command (formerly ":load augz") sets up elvis
+ to automatically handle gzipped files. It has some problems, but
+ the two biggest problems are now fixed.
+
+ One problem was that filtering commands always wrote out the
+ final newline to gunzip, even though that newline wasn't part of
+ the gzipped data. This caused gunzip to output an error message.
+ 2.2.1 doesn't write out the final newline when the
+ "partiallastline" option is set.
+
+ The other main problem was that the file was initially displayed
+ in hex mode, even after the file had been gunzipped into text.
+ To get around this, elvis will now temporarily remove ".gz" from
+ the end of the file name, then rerun the "elvis.arf" script, and
+ then slap the ".gz" back on the file name again so the file can
+ be saved correctly.
+
+ "x11" could generate a BadMatch error while exiting
+ This would occur if you start Elvis from an xterm, and then
+ exited the xterm before Elvis. Elvis will now ignore that
+ particular error.
+
+
+
+The following new features have been added:
+
+ :nofold
+ Wipes out folds. This differs from :unfold in that :unfold
+ leaves some information behind to allow the region to be easily
+ refolded. :nofold leaves nothing behind.
+
+ Persistent information
+ Elvis can store cursor positions and some other things between
+ invocations. See the "persistfile" and "persist" options.
+
+ %< and #< in filenames
+ When giving file name arguments, you can use %< and #< to get
+ the name of the current or alternate file, with its extension
+ removed. For example, if you're editing "database_interface.c",
+ then you can get to "database_interface.h" by typing ":e %<.h".
+
+ :phelp command
+ Like :help except that :phelp doesn't split the screen. Instead,
+ it saves your old cursor position on the tag stack and then
+ shows the help page in your current screen.
+
+ X11 buttons can simulate keystrokes
+ The :gui command accepts a new notation for defining toolbar
+ buttons that simulate keystrokes instead of invoking an ex
+ command. This is useful when you want to do something with a
+ character selection; ex commands treat all selections as line
+ selections.
+
+ The notation uses square brackets around the name. You can put
+ the characters to simulate after the closing square bracket. If
+ you omit those characters, then Elvis will simulate keystrokes
+ that spell out the button name, with the brackets included. You
+ can then set up a :map to convert that to something else. That
+ can be nice because elvis allows maps to be somewhat context
+ sensitive.
+
+ Computed line addresses
+ In ex command lines, you can now use =option to pull a line
+ address from an option, or =(expression) for more complex
+ expressions. This is often handy in aliases.
+
+ GDB interface
+ The core of a simple GDB interface is provided, to allow Elvis
+ and GDB to work together. This depends on Elvis' "x11" user
+ interface; you can't use it with the termcap interface. It is
+ implemented partly as a C program that acts as a "wrapper"
+ around GDB and parses its output for things that Elvis needs to
+ know, and partly as a set of aliases which receive that
+ information and act on it (e.g., by moving the cursor, or
+ changing the highlight of breakpoint lines).
+
+ Generic "state" display
+ A new "state" option has been created. If the "show" option
+ contains the keyword "state", then the value of the "state"
+ option will be displayed at the bottom of the window. This can
+ be handy in complex alias packages. The GDB interface uses it to
+ indicate the debugged program's status.
+
+ More function keys
+ The <F11> and <F12> function keys are now supported on most
+ platforms. I also tried to support shift and control function
+ keys, with some success on Linux.
+
+ :map noselect ...
+ The :map command now supports a noselect flag. This is short for
+ "every context except select".
+
+ :load scripts described
+ I've added a section to the "Tips" chapter describing the
+ scripts in Elvis' library. (These may be loaded via the :load
+ alias.)
+
+ :source can read from a program
+ The :source command has been extended to allow it to read the
+ output of a program, and interpret that output as a series of ex
+ commands. For example, you could create a program that scans an
+ HTML document and outputs a series of :fold commands to allow
+ you to selective hide sections of it.
+
+ incsearch partially supports history
+ When using incremental search, the final search expression is
+ stored in the search history. You can use arrow keys or ^Ok and
+ ^Oj to retrieve a previous search. Full editing is still only
+ supported for non-incremental searches, though.
+
View
21 Makefile.in
@@ -1,5 +1,5 @@
# Makefile.in
-# $Id: Makefile.in,v 2.121 2003/10/21 02:31:00 steve Exp $
+# $Id: Makefile.in,v 2.124 2004/03/19 23:02:53 steve Exp $
#
# Makefile.in should not be modified! The "configure" script reads Makefile.in
# and writes a customized Makefile by editing the values of the following
@@ -71,7 +71,7 @@ FLAGI=-I
# ctags and elvtags are the same program under different names. The $(EXE) on
# the end is just in case this Makefile is reconfigured for an operating
# system which requires the EXE macro to be something like ".exe".
-ALL=elvis$(EXE) ref$(EXE) elvtags$(EXE) elvfmt$(EXE)
+ALL=elvis$(EXE) ref$(EXE) elvtags$(EXE) elvfmt$(EXE) elvgdb$(EXE)
################################################################################
# The installation directories are relative to this
@@ -107,7 +107,7 @@ CP=cp
###############################################################################
# Portable compilation rules
-VERSION=2.2_0
+VERSION=2.2_1
MISC= BUGS README.html COPYING INSTALL Makefile.in configure instman.sh\
elvis.lsm makwin32.bat makmsdos.bat makos2.cmd e2 \
elvis.spec.in Announce-$(VERSION)
@@ -137,12 +137,12 @@ GUIHDRS=$(GNOMEHDRS) $(X11HDRS)
LPSRCS= lpescape.c lpovrtyp.c lpps.c
LPOBJS= lpescape$(OBJ) lpovrtyp$(OBJ) lpps$(OBJ)
HDRS= $(OSHDRS) $(GUIHDRS) autocmd.h buffer.h buffer2.h calc.h color.h\
- cut.h descr.h digraph.h display.h display2.h draw.h draw2.h elvis.h\
- elvisio.h event.h ex.h gui.h gui2.h input.h lowbuf.h lp.h map.h\
- mark.h message.h message2.h misc.h more.h move.h need.h operator.h\
- opsys.h optglob.h options.h regexp.h region.h safe.h scan.h session.h\
- spell.h state.h state2.h tag.h tagsrch.h tagelvis.h version.h vi.h\
- vicmd.h window.h config.h
+ cut.h descr.h digraph.h display.h display2.h draw.h draw2.h elvctype.h\
+ elvis.h elvisio.h event.h ex.h fold.h gui.h gui2.h input.h lowbuf.h\
+ lp.h map.h mark.h message.h message2.h misc.h more.h move.h need.h\
+ operator.h opsys.h optglob.h options.h regexp.h region.h safe.h scan.h\
+ session.h spell.h state.h state2.h tag.h tagsrch.h tagelvis.h version.h\
+ vi.h vicmd.h window.h config.h
SRCS= $(OSSRCS) $(GUISRCS) $(LPSRCS) autocmd.c buffer.c calc.c color.c cut.c\
descr.c digraph.c display.c dmhex.c dmmarkup.c dmnormal.c dmsyntax.c\
draw.c event.c ex.c exaction.c exconfig.c exedit.c exmake.c exsubst.c\
@@ -199,6 +199,9 @@ ref$(EXE): $(REFOBJS)
fmt$(EXE): fmt.c os$(OS)$(SLASH)osdir.c
$(CC) $(CFLAGS) fmt.c -o fmt$(EXE)
+elvgdb$(EXE): elvgdb.c
+ $(CC) $(CFLAGS) elvgdb.c $(LIBS) -o elvgdb$(EXE)
+
verify$(EXE): $(HDRS) verify$(OBJ) $(OBJ1) $(OBJ2)
$(CC) $(CFLAGS) verify$(OBJ) $(OBJ1) $(OBJ2) -o verify$(EXE)
View
384 README.html
@@ -1,17 +1,17 @@
<html><head>
-<title>README.html file for elvis 2.2</title>
-<meta name="description" content="Quick intro to elvis 2.2, with links to source code and binaries">
+<title>README.html file for Elvis 2.2</title>
+<meta name="description" content="Quick intro to Elvis 2.2, with links to source code and binaries">
<meta name="keywords" content="vi, elvis, unix, linux, msdos, win32, windows95 windowsNT, nt, os2, os/2, editor, source">
</head><body>
<center>
-<h1>Quick intro to elvis 2.2, with links to source code and binaries</h1>
+<h1>Quick intro to Elvis 2.2, with links to source code and binaries</h1>
</center>
<strong>CONTENTS</strong>
<ul>
<li><a HREF="#thisfile">1. About this file</a>
-<li><a HREF="#vi">2. Differences between vi and elvis 2.2</a>
+<li><a HREF="#vi">2. Differences between vi and Elvis 2.2</a>
<li><a HREF="#new">3. Differences between 2.1 and 2.2</a>
<ul>
<li><a HREF="#NewEx">3.1 New EX commands</a>
@@ -19,27 +19,28 @@
<li><a HREF="#NewOptions">3.3 New options</a>
<li><a HREF="#OldOptions">3.4 Changed or removed options</a>
</ul>
-<li><a HREF="#links">4. Links to related files</a>
+<li><a HREF="#v221">4. Differences between 2.2.0 and 2.2.1</a>
+<li><a HREF="#links">5. Links to related files</a>
</ul>
<pre graphic>
.---------------------------------------------------------------.
-| <strong>This is not elvis' user manual!</strong> The <em>real</em> documentation for |
-| elvis is located in its online help facility. While running |
-| elvis, enter the command "<code>:help</code>" to see the table of contents.|
+| <strong>This is not Elvis' user manual!</strong> The <em>real</em> documentation for |
+| Elvis is located in its online help facility. While running |
+| Elvis, enter the command "<code>:help</code>" to see the table of contents.|
^---------------------------------------------------------------^</pre>
<h1><a NAME="thisfile">1. About this file</a></h1>
This file is written in the HTML markup language.
You can view it with any WWW viewer, such as Netscape.
-You can also use elvis 2.2 to view it; this version of elvis
+You can also use Elvis 2.2 to view it; this version of Elvis
has the ability to view HTML documents, and print them.
-<p>If elvis 2.2 doesn't automatically start up in HTML mode when you
+<p>If Elvis 2.2 doesn't automatically start up in HTML mode when you
view this file, then you'll need to force it into HTML mode by
giving the command "<code>:display html</code>".
-<h1><a name="vi">2. Differences between vi and elvis 2.2</a></h1>
+<h1><a name="vi">2. Differences between vi and Elvis 2.2</a></h1>
Elvis is a superset of vi.
It runs on more operating systems than vi,
it is free,
@@ -61,7 +62,7 @@
<li>A variety of display modes, including syntax coloring and HTML.
<li>Online help, with hypertext links.
<li>Enhanced tags, to support overloading in C++.
-<li>Network support, so you can load/save files via FTP, or even use elvis as a light-weight Web browser.
+<li>Network support, so you can load/save files via FTP, or even use Elvis as a light-weight Web browser.
<li>Aliases, which allow you to define new ex commands.
<li>Built-in calculator
@@ -69,14 +70,14 @@
<p>For a more complete list, with links to detailed descriptions, check the
online manual.
-You can bring up the online manual by starting elvis and giving the command
+You can bring up the online manual by starting Elvis and giving the command
"<code>:help</code>".
The list of extensions appears after the table of contents and a brief
introduction.
<h1><a name="new">3. Differences between 2.1 and 2.2</a></h1>
-The following is a summary of changes made since the release of elvis 2.1.
+The following is a summary of changes made since the release of Elvis 2.1.
These are in addition to any bug fixes.
<h2><a name="NewEx">3.1 New EX commands</a></h2>
@@ -127,7 +128,7 @@
<dd>Closes all windows except this one.
<dt>:preserve
-<dd>Exit elvis, but don't delete the session file.
+<dd>Exit Elvis, but don't delete the session file.
<dt>:push
<dd>This is similar to <strong>:e</strong>, except that <strong>:push</strong>
@@ -225,7 +226,7 @@
<dl>
<dt>antialias, aasqueeze
<dd>For "x11" only, the <strong>antialias</strong> option controls whether
-elvis will use the Xft library to draw antialiased text.
+Elvis will use the Xft library to draw antialiased text.
Antialiased fonts tend to leave a much larger gap between lines, so the
<strong>aasqueeze</strong> option gives you a way to reduce that gap, and
get more lines on the screen.
@@ -244,8 +245,8 @@
store attributes about the buffer, for use by your own maps and aliases.
<dt>binary
-<dd>This is set to indicate that elvis was invoked with a "-b" flag.
-The default <code>elvis.brf</code> uses this to set the <strong>readeol</strong>
+<dd>This is set to indicate that Elvis was invoked with a "-b" flag.
+The default <code>Elvis.brf</code> uses this to set the <strong>readeol</strong>
option to "binary" when appropriate.
<dt>blinktime
@@ -253,7 +254,7 @@
Setting it to 0 will disable blinking.
<dt>cleantext
-<dd>Controls when elvis erases old text.
+<dd>Controls when Elvis erases old text.
Its value is a comma-delimited set of keywords, which may include
"short", "long", "bs", "input", and/or "ex".
@@ -265,7 +266,7 @@
It's value is a comma-delimited list of keywords, which may include
"dollar", "paren", "space", "special", "tilde", and "wildcard".
Windows users may want to remove the "space" keyword, which will prevent
-elvis from parsing spaces as name delimiters; this will make it easier to
+Elvis from parsing spaces as name delimiters; this will make it easier to
enter names with spaces in them.
<dt>folding
@@ -319,7 +320,7 @@
<dt>prefersyntax
<dd>You can set the <strong>prefersyntax</strong> option to one of
-"never", "writable", "local", or "always" to control when elvis should
+"never", "writable", "local", or "always" to control when Elvis should
start displaying a file in the "syntax" display modes rather than one of
the markup display modes such as "html".
For example, after "<code>:set prefersyntax=writable</code>", whenever you edit
@@ -419,7 +420,332 @@
</dl>
-<h1><a name="links">4. Links to related files</a></h1>
+<h1><a name="v221">4. Differences between 2.2.1 and 2.2.0</h1>
+Elvis 2.2.1 is mostly a bug-fix update of 2.2.0.
+A few new feature crept in though.
+
+<h2>4.1 Fixed bugs</h2>
+<dl>
+
+<dt>:andale was using Luxi Mono fonts
+<dd>The <code>:andale</code> alias (used in the "x11" user interface)
+was actually using Luxi Mono fonts instead of Andale fonts.
+
+<dt>filenamerules broke newline handling
+<dd>When I implemented the filenamerules option in 2.2.0, I accidentally
+broke the way it parses newlines.
+This is important if you remove the <strong>spaces</strong> keyword from
+filenamerules, and then do something like
+"<code>:n `grep foo *.txt`</code>"
+to sets the args list to all files containing "foo".
+
+<dt>HTTP User-agent: header line
+<dd>When sending HTTP requests, Elvis should send a User-agent: header line.
+Some web sites demand this.
+
+<dt>Default button names
+<dd>In the "html" display mode, the &lt;input type=submit&gt; and
+&lt;input type=reset&gt; tags should have the default values "Submit" and
+"Reset" respectively.
+In 2.2.0, they have no default.
+
+<dt>&lt;hr/&gt; shows ------------&gt;
+<dd>The "html" display mode had trouble with tags that end with "/&gt;".
+Elvis would display the &gt; on the screen instead of hiding it.
+
+<dt>&lt;Esc&gt;
+<dd>The &lt;Esc&gt; key should beep when pressed in visual command mode.
+
+<dt>Delayed screen updates in "x11" user interface
+<dd>When a map times out, Elvis wasn't updating the screens immediately
+in the "x11" user interface, which made it hard to detect that the map
+had indeed timed out.
+
+<dt>"d)" could crash
+<dd>In a file full of blank lines, "d)" caused 2.2.0 to dump core.
+
+<dt>:put from a cut buffer
+<dd>The <code>:put<code> command wasn't accepting a cut buffer name argument.
+
+<dt>:dict didn't handle single words
+<dd>The <code>:dict</code> alias (after ":load dict") didn't handle single-word
+queries correctly.
+
+<dt>The directory editor's links were relative to the wrong directory.
+<dd>If you used "<code>:e dirname</code>" to edit the directory "dirname",
+then the links in the generated HTML weren't interpreted as being relative
+to "dirname". They were treated as being relative to the current directory.
+
+<dt>"x11" converts &lt;b&gt; to ^K0062.
+<dd>The "x11" user interface is too aggressive when trying to convert key names
+from angle-bracket notation to raw characters.
+If a map contains an HTML tag such as &lt;b&gt;, and the tag name happens to match
+the name of a key such as the "b" key, then Elvis was trying to convert that
+keystroke into a raw control sequence.
+
+<dt>":normal cwFOO^[" didn't work
+<dd>The c operator was implemented in a way that didn't work in the
+<code>:normal</code> command.
+
+<dt>".IP \(bu 4" had too large of an indent.
+<dd>This is apparently due to the fact that "4" has no explicit scaling suffix,
+and .IP was using the wrong default scaling factor.
+
+<dt>Hard to enter ^ in WinElvis on a Norwegian keyboard
+<dd>WinElvis has always had a hard time with "dead keys", but now I'm hopeful
+that it should work. The ^ key works in Norway now, at least.
+
+<dt>":e +cmd file" didn't work
+<dd>For the <code>:e</code> command and a few others, the "+" flag could only
+handle a line number parameter, not a full ex command line.
+
+<dt>Typos in manual.
+<dd>Many found and fixed.
+Still many more to be found, I'm sure.
+
+<dt>:chregion always changes the comment
+<dd>The :chregion shouldn't change the comment of an existing region unless
+you give a new comment explicitly, or the old comment was merely the old
+font name.
+
+<dt>":set show=spell" doesn't work very well.
+<dd>You need to load the whole dictionary to get good suggestions from the
+spell checker.
+In 2.2.0 you had to turn on the "spellautoload" option, but in 2.2.1 that
+option is on by default.
+
+<dt>:map doesn't list all user-defined maps.
+<dd>2.2.0 assumed that any map tied to a symbolic key was defined by the
+system, so it wouldn't list it unless you said "<code>:map all</code>".
+This means you couldn't see actions mapped to function keys.
+2.2.1 is smarter about this -- it adds a flag to indicate whether the
+map was added by the user or created automatically by the GUI.
+
+<dt>Command names were truncated in error messages.
+<dd>When displaying a "bad command name" error message, 2.2.0 would truncate
+the name at the first character that prevented it from being recognized as
+a command.
+2.2.1 displays the full name of the bad command, exactly as you typed it.
+
+<dt>:man doesn't display backslashes correctly
+<dd>The <code>:man</code> alias didn't handle backslashes very well,
+so pages which use a lot of backslashes such as ":man groff_man" looked bad.
+
+<dt>:%unr doesn't always remove all regions.
+<dd>This mostly occured when running autocmds.
+It also affected the <code>:chregion</code> command.
+
+<dt>:%j only joined two lines
+<dd>The command "<code>:1,%j</code>" joins all lines but "<code>:%j</code>"
+only joined two.
+
+<dt>elvis.ini maps too much
+<dd>The default "elvis.ini" file contained maps without the
+<strong>nosave</strong> flag, so if you ran <code>:mkexrc</code> in an xterm,
+your ~/.elvisrc file would contain maps that are present in all user interfaces
+and for all termcap terminal types.
+
+<dt>:mkexrc can lose GUI-specific options
+<dd>The <code>:mkexrc</code> command only saved GUI-specific options for the
+current GUI.
+This means that running <code>:mkexrc</code> in the "termcap" interface could
+clobber your default font for the "x11" interface.
+2.2.1 gets around this by storing all GUI-specific options, even those for
+other GUIs or unknown GUIs, just so it can save them in the ~/.elvisrc file.
+
+<dt>&lt;li&gt;&lt;p&gt; looks ugly
+<dd>Many HTML documents use this sequence of tags to generate lists that have
+a bit of vertical whitespace between items.
+But 2.2.0 was drawing the list item marker (bullet or number) on the blank
+line, instead of the line where the paragraph's text starts.
+2.2.1 treats this as a special case -- it ignores the &lt;p&gt; in this context.
+
+<dt>security=safer is too strict
+<dd>The "security=safer" setting didn't allow some command that it should
+have allowed.
+This prevented some harmless and useful commands such as "elvis -client foo"
+from working.
+To get this working right, I had to overhaul the behavior of "security=safer".
+It is no longer a more lenient superset of "security=restricted".
+See ":help set security" for details.
+
+<p>One consequence of this is that the "-S" flag now sets security=restricted.
+
+<dt>:wq didn't work when security=safer or security=restricted.
+<dd>The manual said it should.
+The new version of security=safer doesn't allow any writing, but you can
+now <code>:wq</code> when security=restricted.
+
+<dt>The "ax" text object didn't support tag names with hyphens
+<dd>I've extended it to allow single hyphens but not double hyphens
+(since double hyphens mark comments).
+It also allows colons, for namespace control.
+
+<dt>dirperm(".") returns readonly
+<dd>The <code>dirperm()</code> function didn't recognize directories
+correctly.
+This was a bug in the way the "dir:" pseudo-protocol was implemented.
+
+<dt>hlobject didn't allow commas
+<dd>An increasing number of options in elvis store multiple values in
+comma-delimited lists.
+The "hlobject" option can store multiple values, but required them to
+be either crammed together or delimited by spaces.
+Now it supports commas.
+
+<dt>rcssince didn't work
+<dd>The rcssince alias (part of ":load since") is supposed to be executed
+when a buffer is loaded, but it used some commands which are illegal during
+initialization.
+Most of the commands that are illegal during initialization are only
+illegal because they're useless until the first file is loaded into a buffer.
+The rcssince alias was actually running after the file was loaded, so it
+should be allowed, but Elvis had a rather weak idea of when "initialization"
+ends.
+
+<dt>:suspend didn't work
+<dd>It wasn't in Elvis' internal command list correctly.
+The <code>:stop</code> equivalent has always worked though.
+
+<dt>Backslashes aren't handled right in "simpler syntax"
+<dd>If a "simpler syntax" expression started with \( or \$ then Elvis
+should convert that to a literal ( or $ character.
+Instead, 2.2.0 was leaving it as a literal \ followed by an parenthesized
+subexpression, or $ variable substitution.
+(This arose from trying to make an initial \\ remain unchanged so Windows
+users could five UNC names such as \\machine\dir\file.)
+
+<dt>AliasLeave events
+<dd>At the end of an alias, 2.2.0 generated an AliasEnter event when it
+should have generated an AliasLeave event.
+
+<dt>:eval does not compute
+<dd>The :eval command could get confused if the command that it runs
+needs to evaluate an expression.
+This was because a static buffer is used to return the results of evaluations,
+and :eval didn't copy the result into a local buffer before trying to execute
+it.
+
+<dt>Trouble with gzipped files
+<dd>The "<code>:load gzip</code>" command (formerly "<code>:load augz</code>")
+sets up elvis to automatically handle gzipped files.
+It has some problems, but the two biggest problems are now fixed.
+<p>One problem was that filtering commands always wrote out the final newline
+to gunzip, even though that newline wasn't part of the gzipped data.
+This caused gunzip to output an error message.
+2.2.1 doesn't write out the final newline when the "partiallastline" option
+is set.
+<p>The other main problem was that the file was initially displayed in hex
+mode, even after the file had been gunzipped into text.
+To get around this, elvis will now temporarily remove ".gz" from the end of
+the file name, then rerun the "elvis.arf" script, and then slap the ".gz"
+back on the file name again so the file can be saved correctly.
+
+<dt>"x11" could generate a BadMatch error while exiting
+<dd>This would occur if you start Elvis from an xterm,
+and then exited the xterm before Elvis.
+Elvis will now ignore that particular error.
+
+</dl>
+
+<h2>4.2 New features</h2>
+<dl>
+
+<dt>:nofold
+<dd>Wipes out folds. This differs from <code>:unfold</code> in that
+<code>:unfold</code> leaves some information behind to allow the region to
+be easily refolded. <code>:nofold</code> leaves nothing behind.
+
+<dt>Persistent information
+<dd>Elvis can store cursor positions and some other things between invocations.
+See the "persistfile" and "persist" options.
+
+<dt>%&lt; and #&lt; in filenames
+<dd>When giving file name arguments, you can use %&lt; and #&lt; to get the name of
+the current or alternate file, with its extension removed.
+For example, if you're editing "database_interface.c", then you can get to
+"database_interface.h" by typing "<code>:e %&lt;.h</code>".
+
+<dt>:phelp command
+<dd>Like <code>:help</code> except that <code>:phelp</code> doesn't split
+the screen.
+Instead, it saves your old cursor position on the tag stack and then shows
+the help page in your current screen.
+
+<dt>X11 buttons can simulate keystrokes
+<dd>The <code>:gui</code> command accepts a new notation for defining toolbar
+buttons that simulate keystrokes instead of invoking an ex command.
+This is useful when you want to do something with a character selection;
+ex commands treat all selections as line selections.
+
+<p>The notation uses square brackets around the name.
+You can put the characters to simulate after the closing square bracket.
+If you omit those characters, then Elvis will simulate keystrokes that
+spell out the button name, with the brackets included.
+You can then set up a <code>:map</code> to convert that to something else.
+That can be nice because elvis allows maps to be somewhat context sensitive.
+
+<dt>Computed line addresses
+<dd>In ex command lines, you can now use
+<code>=</code><var>option</var> to pull a line address from an option, or
+<code>=(</code><var>expression</var><code>)</code> for more complex expressions.
+This is often handy in aliases.
+
+<dt>GDB interface
+<dd>The core of a simple GDB interface is provided,
+to allow Elvis and GDB to work together.
+This depends on Elvis' "x11" user interface; you can't use it with the termcap
+interface.
+It is implemented partly as a C program that acts as a "wrapper" around GDB
+and parses its output for things that Elvis needs to know, and partly as a
+set of aliases which receive that information and act on it (e.g., by moving
+the cursor, or changing the highlight of breakpoint lines).
+
+<dt>Generic "state" display
+<dd>A new "state" option has been created.
+If the "show" option contains the keyword "state", then the value of the
+"state" option will be displayed at the bottom of the window.
+This can be handy in complex alias packages.
+The GDB interface uses it to indicate the debugged program's status.
+
+<dt>More function keys
+<dd>The &lt;F11&gt; and &lt;F12&gt; function keys are now supported on most
+platforms.
+I also tried to support shift and control function keys, with some success
+on Linux.
+
+<dt>:map noselect ...
+<dd>The :map command now supports a <strong>noselect</strong> flag.
+This is short for "every context except select".
+
+<dt>:load scripts described
+<dd>I've added a section to the "Tips" chapter describing the scripts
+in Elvis' library.
+(These may be loaded via the <code>:load</code> alias.)
+
+<dt>:source can read from a program
+<dd>The :source command has been extended to allow it to read the output of
+a program, and interpret that output as a series of ex commands.
+For example, you could create a program that scans an HTML document and
+outputs a series of <code>:fold</code> commands to allow you to selective
+hide sections of it.
+
+<dt>incsearch partially supports history
+<dd>When using incremental search, the final search expression is stored
+in the search history.
+You can use arrow keys or ^Ok and ^Oj to retrieve a previous search.
+Full editing is still only supported for non-incremental searches, though.
+
+<dt>herefile script
+<dd>After "<code>:load herefile</code>", Elvis should be able to highlight
+"herefiles" in shell scripts.
+Herefiles are text files embedded within the script itself, between
+<code>&lt;&lt;</code><var>SYMBOL</var> and a line containing just
+<var>SYMBOL</var>.
+
+</dl>
+
+<h1><a name="links">5. Links to related files</a></h1>
The main download site is
<a href="ftp://ftp.cs.pdx.edu/pub/elvis/">ftp.cs.pdx.edu</a>.
@@ -461,8 +787,8 @@
DOS programs won't be able to find them with their expected names,
and vice versa.
Consequently, you must use <code>untardos.exe</code> to unpack
-<code>elvis-2.2_0-msdos.tar.gz</code>, and <code>untarw32.exe</code> to unpack
-<code>elvis-2.2_0-win32.tar.gz</code>.
+<code>elvis-2.2_1-msdos.tar.gz</code>, and <code>untarw32.exe</code> to unpack
+<code>elvis-2.2_1-win32.tar.gz</code>.
(Actually, I recently added a <strong>-m</strong> flag which forces
<code>untarw32.exe</code> to convert long file names to short ones using
the MS-DOS method.)
@@ -472,21 +798,21 @@
For brief instructions on how to use <code>untaros2,</code>
run it with no arguments.
-<dt><a href="elvis-2.2_0.tar.gz">elvis-2.2_0.tar.gz</a>
+<dt><a href="elvis-2.2_1.tar.gz">elvis-2.2_1.tar.gz</a>
<dd>This is a gzipped tar archive of the source code and documentation for
Elvis 2.2 and its related programs.
-<dt><a href="elvis-2.2_0-msdos.tar.gz">elvis-2.2_0-msdos.tar.gz</a>
+<dt><a href="elvis-2.2_1-msdos.tar.gz">elvis-2.2_1-msdos.tar.gz</a>
<dd>This archive contains the documentation and MS-DOS executables
for Elvis 2.2.
-<dt><a href="elvis-2.2_0-win32.tar.gz">elvis-2.2_0-win32.tar.gz</a>
+<dt><a href="elvis-2.2_1-win32.tar.gz">elvis-2.2_1-win32.tar.gz</a>
<dd>This archive contains the documentation and Win32 executables
for Elvis 2.2.
These were compiled and tested under Windows95, but should work under
WindowsNT 3.51 (or later) as well.
-<dt><a href="elvis-2.2_0-os2.tar.gz">elvis-2.2_0-os2.tar.gz</a>
+<dt><a href="elvis-2.2_1-os2.tar.gz">elvis-2.2_1-os2.tar.gz</a>
<dd>This archive contains the documentation and OS/2 executables
for Elvis 2.2.
<strong>If this link is broken then look in Herbert's site, below.</strong>
@@ -495,7 +821,7 @@
<a href="http://www.fh-wedel.de/pub/fh-wedel/staff/di/elvis/00-index.html">
http://www.fh-wedel.de/pub/fh-wedel/staff/di/elvis/00-index.html</a>
<dd>This is where the OS/2 maintainer stores his most up-to-date versions.
-It may be better than the <code>elvis-2.2_0-os2.tar.gz</code> file, above.
+It may be better than the <code>elvis-2.2_1-os2.tar.gz</code> file, above.
</dl>
</body></html>
View
54 autocmd.c
@@ -4,7 +4,7 @@
#include "elvis.h"
#ifdef FEATURE_RCSID
-char id_autocmd[] = "$Id: autocmd.c,v 1.30 2003/10/19 23:13:33 steve Exp $";
+char id_autocmd[] = "$Id: autocmd.c,v 1.32 2004/03/21 23:24:41 steve Exp $";
#endif
#ifdef FEATURE_AUTOCMD
@@ -55,7 +55,7 @@ static struct {
} nametbl[] =
{
{ toCHAR("*"), {0x7fffffff, 0x3fffffff, 0x3fffffff}},
- { toCHAR("*"),/* without OPTBITS */ {0x7fffffff, 0x3ffff9ff, 0x3fffffff}},
+ { toCHAR("*"),/* without OPTBITS */ {0x7fffffff, 0x3fff3fff, 0x3fffffff}},
/* file events */
{ toCHAR("BufCreate"), {0x00000001, 0x00000000, 0x00000000}},
@@ -147,7 +147,9 @@ static struct {
{ NULL, /* AU_USER29 */ {0x00000000, 0x00000000, 0x10000000}},
{ NULL, /* AU_USER30 */ {0x00000000, 0x00000000, 0x20000000}},
};
-#define OPTBITS 0x00003000
+#define OPTBITS 0x0000c000 /* aubits.otherevents, OptSet and OptChanged */
+#define UGLYBIT 0x40000000 /* aubits.otherevents, marks old synonym */
+#define BANGBIT 0x40000000 /* aubits.userevents, marks :auevent! names */
#ifdef USE_PROTOTYPES
static ELVBOOL wildmatch(char *fname, char *wildlist);
@@ -341,10 +343,10 @@ static aubits_t *nametobits(name)
}
/* strip off the "ugly" bit */
- bits.otherevents &= ~0x40000000;
+ bits.otherevents &= ~UGLYBIT;
/* strip off the "internal" bit */
- bits.userevents &= ~0x40000000;
+ bits.userevents &= ~BANGBIT;
/* return the combined bits */
return &bits;
@@ -368,7 +370,7 @@ static CHAR *bitstoname(aubits)
nbits = &nametbl[i].bits;
if ((bits.fileevents & nbits->fileevents) != nbits->fileevents
|| (bits.otherevents & nbits->otherevents) != nbits->otherevents
- || (bits.userevents & nbits->userevents) != (nbits->userevents & ~0x40000000))
+ || (bits.userevents & nbits->userevents) != (nbits->userevents & ~BANGBIT))
continue;
/* add this event to the name */
@@ -437,8 +439,8 @@ RESULT ex_auevent(xinf)
continue;
/* skip if is/isn't set up using standard scripts */
- if ((nametbl[i].bits.userevents & 0x40000000) !=
- (long)(xinf->bang ? 0x40000000 : 0x0))
+ if ((nametbl[i].bits.userevents & BANGBIT) !=
+ (long)(xinf->bang ? BANGBIT : 0x0))
continue;
/* output a space or newline, if necessary */
@@ -490,7 +492,7 @@ RESULT ex_auevent(xinf)
/* also mark it as being "internal" if ! flag */
if (xinf->bang)
- nametbl[i].bits.userevents |= 0x40000000;
+ nametbl[i].bits.userevents |= BANGBIT;
ContinueContinue:
;
}
@@ -977,7 +979,7 @@ RESULT auperform(win, bang, groupname, event, filename)
}
/* if requested group not found, fail */
- if (!anygrp)
+ if (groupname && !anygrp)
{
msg(MSG_ERROR, "no such augroup");
goto Error;
@@ -1044,29 +1046,23 @@ void ausave(custom)
BUFFER custom; /* the buffer to which the :au commands are added */
{
ELVBOOL anygrp; /* any groups output yet? */
- MARKBUF end;
aug_t *group;
au_t *au;
CHAR *cmd, *word;
int i;
- end.buffer = custom;
-
/* for each event... */
for (i = 2; i < QTY(nametbl) && nametbl[i].name; i++)
{
/* skip if built-in, or defined in a standard script */
if (nametbl[i].bits.userevents == 0
- || (nametbl[i].bits.userevents & 0x40000000) != 0)
+ || (nametbl[i].bits.userevents & BANGBIT) != 0)
continue;
/* output a command to recreate this event type */
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("try aue "), 8L);
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, nametbl[i].name, (long)CHARlen(nametbl[i].name));
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("\n"), 1L);
+ bufappend(custom, toCHAR("try aue "), 8L);
+ bufappend(custom, nametbl[i].name, 0);
+ bufappend(custom, toCHAR("\n"), 1L);
}
/* for each group... */
@@ -1080,12 +1076,9 @@ void ausave(custom)
anygrp = ElvTrue;
/* start this group */
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("try aug "), 8L);
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, group->group, (long)CHARlen(group->group));
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("\nthen {\n au!\n"), 13L);
+ bufappend(custom, toCHAR("try aug "), 8L);
+ bufappend(custom, group->group, 0);
+ bufappend(custom, toCHAR("\nthen {\n au!\n"), 13L);
/* for each au in this group... */
for (au = group->au; au; au = au->next)
@@ -1126,8 +1119,7 @@ void ausave(custom)
}
/* add the command to the buffer */
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, cmd, CHARlen(cmd));
+ bufappend(custom, cmd, CHARlen(cmd));
/* free the string form of the command */
safefree(cmd);
@@ -1135,16 +1127,14 @@ void ausave(custom)
} /* for au */
/* mark the end of this group */
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("}\n"), 2);
+ bufappend(custom, toCHAR("}\n"), 2);
} /* for group */
/* if any groups were output, then we need to end "if feature(...)" */
if (anygrp)
{
- end.offset = o_bufchars(custom);
- bufreplace(&end, &end, toCHAR("try aug END\n"), 12L);
+ bufappend(custom, toCHAR("try aug END\n"), 12L);
}
}
# endif /* FEATURE_MKEXRC */
View
938 buffer.c
@@ -4,7 +4,7 @@
#include "elvis.h"
#ifdef FEATURE_RCSID
-char id_buffer[] = "$Id: buffer.c,v 2.150 2003/10/17 17:41:23 steve Exp $";
+char id_buffer[] = "$Id: buffer.c,v 2.160 2004/03/23 18:23:16 steve Exp $";
#endif
#define swaplong(x,y) {long tmp; tmp = (x); (x) = (y); (y) = tmp;}
@@ -18,6 +18,14 @@ static void didmodify(BUFFER buf);
static void proc(_BLKNO_ bufinfo, long nchars, long nlines, long changes,
long prevloc, CHAR *name);
# endif
+# ifdef FEATURE_PERSIST
+static CHAR *persistget(void);
+static void persistload(BUFFER buf);
+static ELVBOOL persistinternal(BUFFER buf);
+static void persisthist(char *field, char *prompt, char *bufname, BUFFER persbuf);
+static void persistbuf(BUFFER buf, BUFFER persbuf);
+static void persistother(BUFFER buf, BUFFER persbuf);
+# endif
# ifdef DEBUG_ALLOC
static void checkundo(char *where);
static void removeundo(struct undo_s *undo);
@@ -297,6 +305,812 @@ void bufinit()
bufoptions(bufdefopts);
}
+#ifdef FEATURE_PERSIST
+/* Return ElvTrue if a buffer is internal (not persistent) */
+static ELVBOOL persistinternal(buf)
+ BUFFER buf; /* a buffer to be saved, or NULL for all */
+{
+ /* all buffers can't be internal */
+ if (!buf)
+ return ElvFalse;
+
+ if (o_internal(buf)
+ || !CHARncmp(o_bufname(buf), toCHAR("Elvis untitled"), 14)
+ || !o_filename(buf))
+ return ElvTrue;
+
+ return ElvFalse;
+}
+
+
+/* Return the next line, or NULL if there is no next line. The \n is stripped
+ * off, but there's guaranteed to be room in the buffer for it, so you can
+ * CHARcat(line, toCHAR("\n")) to put it back. This function assumes you've
+ * already called ioopen() to start reading the file.
+ */
+static CHAR *persistget()
+{
+ static CHAR line[300];
+ CHAR *val;
+
+ /* fetch the next line */
+ *line = '\0';
+ for (val = line;
+ val < &line[QTY(line) - 1]
+ && ioread(val, 1) == 1
+ && *val != '\n';
+ val++)
+ {
+ }
+
+ /* if nothing read, then return NULL */
+ if (*line == '\0')
+ return NULL;
+
+ /* return the line */
+ *val = '\0';
+ return line;
+}
+
+/* Load global persistent information */
+void bufpersistinit()
+{
+ ELVBOOL doex, dosearch, doargs;
+ BUFFER exbuf, searchbuf;
+ CHAR *line;
+ int i, nargs;
+ char **newargs;
+ int gotnext;
+ ELVBOOL oldhide;
+
+ /* do nothing if persistfile is unset */
+ if (!o_persistfile)
+ return;
+
+ /* figure out what we're supposed to load */
+ doex = (ELVBOOL)(calcelement(o_persist,toCHAR("ex")) != NULL);
+ dosearch = (ELVBOOL)(calcelement(o_persist,toCHAR("search")) != NULL);
+ doargs = (ELVBOOL)(calcelement(o_persist,toCHAR("args")) != NULL);
+ if (arglist && *arglist)
+ doargs = ElvFalse; /* already have args */
+
+ /* if not supposed to do any globals, then don't */
+ if (!doex && !dosearch && !doargs)
+ return;
+
+ /* try to open the file */
+ oldhide = msghide(ElvTrue);
+ if (!ioopen(iofilename(tochar8(o_persistfile), '\0'), 'r', ElvFalse, ElvFalse, 't'))
+ {
+ (void)msghide(oldhide);
+ return;
+ }
+ (void)msghide(oldhide);
+
+ /* locate the history buffers */
+ exbuf = bufalloc(toCHAR(EX_BUF), 0, ElvTrue);
+ searchbuf = bufalloc(toCHAR(REGEXP_BUF), 0, ElvTrue);
+
+ /* for each line up to the first bufname line... */
+ nargs = 0;
+ gotnext = -1;
+ while ((line = persistget()) != NULL && CHARncmp(line, "bufname ", 8))
+ {
+ /* skip blank lines. */
+ if (!*line)
+ continue;
+
+ /* handle it */
+ if (*line == ':')
+ {
+ /* skip if not doing ex history */
+ if (!doex)
+ continue;
+
+ /* append to ex history */
+ CHARcat(line, toCHAR("\n"));
+ bufappend(exbuf, line, 0);
+ }
+ else if (*line == '/' || *line == '?')
+ {
+ /* skip of not doing search history */
+ if (!dosearch)
+ continue;
+
+ /* append to search history */
+ CHARcat(line, toCHAR("\n"));
+ bufappend(searchbuf, line, 0);
+ }
+ else if (!CHARncmp(line, "arg ", 4))
+ {
+ /* skip if not doing args */
+ if (!doargs)
+ continue;
+
+ /* append to the args list */
+ newargs = safealloc(nargs + 2, sizeof(char *));
+ for (i = 0; i < nargs; i++)
+ newargs[i] = arglist[i];
+ newargs[nargs++] = safedup(tochar8(line + 4));
+ newargs[nargs] = NULL;
+ if (arglist)
+ safefree(arglist);
+ arglist = newargs;
+ }
+ else if (!CHARncmp(line, "argnext ", 8))
+ {
+ /* skip if not doing args */
+ if (!doargs)
+ continue;
+
+ /* remember the "argnext" value for later */
+ gotnext = (int)CHAR2long(line + 8);
+ }
+ }
+
+ /* maybe restore argnext */
+ if (doargs && gotnext > 0 && gotnext <= nargs)
+ argnext = gotnext - 1; /* so we start on the one before next */
+
+ /* close the file */
+ (void)ioclose();
+}
+
+/* Load the peristent information about a given buffer */
+static void persistload(buf)
+ BUFFER buf;
+{
+ CHAR *line;
+ char *line8;
+ long cursor, change; /* found cursor & change */
+ int hours; /* age of found timestamp for entry */
+ int gotYYYY, gotMM, gotDD, gothh, gotmm; /* parsed timestamp */
+ int nowYYYY, nowMM, nowDD, nowhh, nowmm; /* parsed current time */
+ ELVBOOL domarks; /* supposed to load marks? */
+ ELVBOOL skip;
+ char markname[2];
+ CHAR *phours;
+ long value;
+ int i;
+ ELVBOOL oldhide;
+ long oldbuflines, oldbufchars;
+ CHAR *external;
+#ifdef FEATURE_REGION
+ ELVBOOL doregions; /* supposed to load regions? */
+ int regions; /* found number of regions */
+ _char_ face;
+ char facename[50];
+#endif
+#ifdef FEATURE_FOLD
+ ELVBOOL dofolds; /* supposed to load folds? */
+ int folds; /* found number of folds */
+ FOLD newfold;
+#endif
+#if defined(FEATURE_REGION) || defined(FEATURE_FOLD)
+ long top, bottom;
+ MARKBUF marktop, markbottom;
+ char comment[300];
+#endif
+
+ /* if the persistfile option is unset, then do nothing */
+ if (!o_persistfile)
+ return;
+
+ /* do nothing for internal buffers, buffers without a filename, or
+ * untitled buffers.
+ */
+ if (persistinternal(buf))
+ return;
+
+ /* Try to open the file */
+ oldhide = msghide(ElvTrue);
+ if (!ioopen(iofilename(tochar8(o_persistfile), '\0'), 'r', ElvFalse, ElvFalse, 't'))
+ {
+ (void)msghide(oldhide);
+ return;
+ }
+ (void)msghide(oldhide);
+
+ /* detect whether we're supposed to load some specific things */
+ domarks = (ELVBOOL)(calcelement(o_persist,toCHAR("marks")) != NULL);
+#ifdef FEATURE_REGION
+ doregions = (ELVBOOL)(calcelement(o_persist,toCHAR("regions")) != NULL);
+#endif
+#ifdef FEATURE_FOLD
+ dofolds = (ELVBOOL)(calcelement(o_persist,toCHAR("folds")) != NULL);
+#endif
+
+ /* for now, assume buflines and bufchars won't change */
+ oldbuflines = o_buflines(buf);
+ oldbufchars = o_bufchars(buf);
+ external = calcelement(o_persist, toCHAR("external"));
+ if (external && *external == ':')
+ external++;
+ else
+ external = toCHAR("b");
+
+ /* For each line... */
+ cursor = change = -1L;
+ hours = 0;
+#ifdef FEATURE_REGION
+ regions = 0;
+#endif
+#ifdef FEATURE_FOLD
+ folds = 0;
+#endif
+ skip = ElvTrue;
+ while ((line = persistget()) != NULL)
+ {
+ /* is it a bufname line? */
+ if (!CHARncmp(line, toCHAR("bufname "), 8))
+ {
+ /* is this the end of this buffer's section? */
+ if (!skip)
+ break;
+
+ /* is it the start of this buffer's section */
+ skip = (ELVBOOL)(CHARcmp(line+8, o_bufname(buf)) != 0);
+ }
+
+ /* skip if not for this buffer */
+ if (skip)
+ continue;
+
+ /* is it the entry's timestamp? */
+ line8 = tochar8(line);
+ if (sscanf(line8, "hours %4d%2d%2dT%2d:%2d",
+ &gotYYYY, &gotMM, &gotDD, &gothh, &gotmm) == 5)
+ {
+ /* get the current timestamp */
+ sscanf(dirtime(NULL), "%4d%2d%2dT%2d:%2d",
+ &nowYYYY, &nowMM, &nowDD, &nowhh, &nowmm);
+
+ /* compute the hours between them (sloppily) */
+ if (nowYYYY > gotYYYY)
+ nowMM += 12;
+ if (nowMM > gotMM)
+ nowDD += 28;/* best to err on the low side */
+ hours = ((nowmm - gotmm) + 60 * (nowhh - gothh) + 1440 * (nowDD - gotDD)) / 60;
+ continue;
+ }
+
+ /* is it the number of expected lines or characters? */
+ if (sscanf(line8, "bufchars %ld", &value) == 1)
+ {
+ oldbufchars = value;
+ continue;
+ }
+ if (sscanf(line8, "buflines %ld", &value) == 1)
+ {
+ oldbuflines = value;
+ continue;
+ }
+
+ /* is it the cursor? */
+ if (sscanf(line8, "cursor %ld", &value) == 1)
+ {
+ /* adjust for external changes */
+ switch (*external)
+ {
+ case 't':
+ /* adjust relative to bottom */
+ value += o_bufchars(buf) - oldbufchars;
+ break;
+
+ case 's':
+ /* skip if different */
+ if (oldbufchars != o_bufchars(buf))
+ continue;
+ break;
+ }
+
+ /* store the value as the buffer's "docursor" */
+ if (value >= 0 && value < o_bufchars(buf))
+ cursor = value;
+ continue;
+ }
+
+ /* is it the change position? */
+ if (sscanf(line8, "change %ld", &value) == 1)
+ {
+ /* adjust for external changes */
+ switch (*external)
+ {
+ case 't':
+ /* adjust relative to bottom */
+ value += o_bufchars(buf) - oldbufchars;
+ break;
+
+ case 's':
+ /* skip if different */
+ if (oldbufchars != o_bufchars(buf))
+ continue;
+ break;
+ }
+
+ /* store the value as the buffer's "last change" */
+ if (value >= 0 && value < o_bufchars(buf))
+ change = value;
+ continue;
+ }
+
+ /* is it a specific mark? and do we care? */
+ if (sscanf(line8, "mark %1[a-z] %ld", markname, &value) == 2)
+ {
+ /* if not doing marks, then skip it */
+ if (!domarks)
+ continue;
+
+ /* adjust for external changes */
+ switch (*external)
+ {
+ case 't':
+ /* adjust relative to bottom */
+ value += o_bufchars(buf) - oldbufchars;
+ break;
+
+ case 's':
+ /* skip if different */
+ if (oldbufchars != o_bufchars(buf))
+ continue;
+ break;
+ }
+
+ /* if invalid position, then skip it */
+ if (value < 0 || value >= o_bufchars(buf))
+ continue;
+
+ /* restore the mark */
+ i = markname[0] - 'a';
+ if (namedmark[i])
+ {
+ marksetbuffer(namedmark[i], buf);
+ marksetoffset(namedmark[i], value);
+ }
+ else
+ {
+ namedmark[i] = markalloc(buf, value);
+ }
+ continue;
+ }
+
+#ifdef FEATURE_REGION
+ /* is it a region? */
+ if (sscanf(line8, "region %ld,%ld %s %[^\n]", &top, &bottom, facename, comment) == 4)
+ {
+ /* skip if not doing regions */
+ if (!doregions)
+ continue;
+
+ /* adjust for external changes */
+ switch (*external)
+ {
+ case 't':
+ /* adjust relative to bottom */
+ top += o_buflines(buf) - oldbuflines;
+ bottom += o_buflines(buf) - oldbuflines;
+ break;
+
+ case 's':
+ /* skip if different */
+ if (oldbuflines != o_buflines(buf))
+ continue;
+ break;
+ }
+
+ /* skip if invalid */
+ if (top < 1 || top > bottom || bottom > o_buflines(buf))
+ continue;
+
+ /* rebuild the region */
+ face = colorfind(toCHAR(facename));
+ if (!face)
+ break;
+ regionadd(marksetline(marktmp(marktop, buf, 0), top),
+ marksetline(marktmp(markbottom, buf, 0), bottom+1),
+ face, toCHAR(comment));
+ }
+#endif /* FEATURE_REGION */
+
+#ifdef FEATURE_FOLD
+ /* is it a fold or unfold? */
+ if (sscanf(line8, " fold %ld,%ld %[^\n]",
+ &top, &bottom, comment) == 3
+ || sscanf(line8, " unfold %ld,%ld %[^\n]",
+ &top, &bottom, comment) == 3)
+ {
+ /* skip if we aren't doing folds */
+ if (!dofolds)
+ continue;
+
+ /* adjust for external changes */
+ switch (*external)
+ {
+ case 't':
+ /* adjust relative to bottom */
+ top += o_buflines(buf) - oldbuflines;
+ bottom += o_buflines(buf) - oldbuflines;
+ break;
+
+ case 's':
+ /* skip if different */
+ if (oldbuflines != o_buflines(buf))
+ continue;
+ break;
+ }
+
+ /* skip if invalid */
+ if (top < 1 || top > bottom || bottom > o_buflines(buf))
+ continue;
+
+ /* create the new fold */
+ (void)marksetline(marktmp(marktop, buf, 0), top);
+ (void)marksetline(marktmp(markbottom, buf, 0),bottom+1);
+ markaddoffset(&markbottom, -1L);
+ newfold = foldalloc(&marktop, &markbottom, toCHAR(comment));
+
+ /* there shouldn't be any overlapping folds,
+ * but just to be safe...
+ */
+ (void)foldbyrange(newfold->from, newfold->to,
+ ElvTrue, FOLD_NOEXTRA|FOLD_DESTROY);
+ (void)foldbyrange(newfold->from, newfold->to,
+ ElvFalse, FOLD_NOEXTRA|FOLD_DESTROY);
+
+ /* add it as a fold or unfold */
+ foldadd(newfold, (ELVBOOL)(*line8 == 'f'));
+ }
+#endif /* FEATURE_FOLD */
+ }
+
+ /* close the file */
+ (void)ioclose();
+
+ /* get the persist.hours value */
+ phours = calcelement(o_persist, toCHAR("hours"));
+ if (phours)
+ phours++;
+
+ /* clobber cursor and/or change, if not supposed to load */
+ if (!calcelement(o_persist, toCHAR("cursor")))
+ cursor = -1L;
+ if (!calcelement(o_persist, toCHAR("change")))
+ change = -1L;
+
+ /* if it hasn't expired then restore cursor */
+ if (!phours || hours < atoi(tochar8(phours)))
+ {
+ if (cursor >= 0)
+ {
+ buf->docursor = cursor;
+ if (change >= 0)
+ buf->changepos = change;
+ }
+ else if (change >= 0)
+ buf->docursor = change;
+ }
+ else /* maybe still restore '' mark */
+ {
+ if (cursor >= 0)
+ buf->changepos = cursor;
+ else if (change >= 0)
+ buf->changepos = change;
+ }
+}
+
+/* Append the end of a history buffer to persbuf */
+static void persisthist(field, prompt, bufname, persbuf)
+ char *field; /* name of field in 'persist' option */
+ char *prompt; /* acceptable prompt characters: ":" or "/?" */
+ char *bufname; /* name of buffer containing history */
+ BUFFER persbuf; /* temp buffer used to construct persistfile */
+{
+ long lines; /* number of lines to keep */
+ CHAR *scan;
+ BUFFER histbuf;
+ MARK mark;
+ MARKBUF histeol, persend;
+
+ /* locate the history buffer. If not found, there's nothing to save */
+ histbuf = buffind(toCHAR(bufname));
+ if (!histbuf || o_bufchars(histbuf) == 0L)
+ return;
+
+ /* get the number of lines to keep. If 0, then save nothing */
+ scan = calcelement(o_persist, toCHAR(field));
+ if (!scan || *scan++ != ':')
+ return;
+ for (lines = 0; elvdigit(*scan); scan++)
+ lines = lines * 10 + *scan - '0';
+ if (lines == 0)
+ return;
+
+ /* locate the first line to copy */
+ mark = markalloc(histbuf, 0L);
+ if (lines < o_buflines(histbuf))
+ marksetline(mark, o_buflines(histbuf) - lines + 1);
+
+ /* for each line in history ... */
+ scanalloc(&scan, mark);
+ for(;;)
+ {
+ /* find the end of the line */
+ while (scan && *scan != '\n')
+ scannext(&scan);
+ if (!scan)
+ break;
+ scannext(&scan);
+
+ /* if line starts with prompt char, then copy it */
+ if (CHARchr(toCHAR(prompt), scanchar(mark)) != NULL)
+ {
+ /* need to stop scanning while changing */
+ if (scan)
+ histeol = *scanmark(&scan);
+ else
+ {
+ histeol.buffer = histbuf;
+ histeol.offset = o_bufchars(histbuf);
+ }
+
+ /* copy the history to the end of the persist buffer */
+ bufpaste(marktmp(persend, persbuf, o_bufchars(persbuf)),
+ mark, &histeol);
+
+ /* resume scanning. we changed persbuf, not histbuf, * so the offset of previous scan should be good
+ */
+ if (scan)
+ scanalloc(&scan, &histeol);
+ }
+
+ /* move the mark to the start of the next line */
+ if (!scan)
+ break;
+ marksetoffset(mark, histeol.offset);
+ }
+
+ markfree(mark);
+}
+
+/* Append information describing one buffer */
+static void persistbuf(buf, persbuf)
+ BUFFER buf; /* the buffer to be stored */
+ BUFFER persbuf;/* temp buffer used to construct new persistfile */
+{
+ char line[300];
+ int i;
+#ifdef FEATURE_REGION
+ struct region_s *region;
+#endif
+#ifdef FEATURE_FOLD
+ FOLD fold;
+#endif
+
+ /* always start with a "bufname" line, and timestamp */
+ sprintf(line, "bufname %.289s\nhours %s\n",
+ o_bufname(buf), dirtime(NULL));
+ bufappend(persbuf, toCHAR(line), 0);
+
+ /* always store bufchars, buflines, cursor, and change */
+ sprintf(line, "bufchars %ld\nbuflines %ld\ncursor %ld\nchange %ld\n",
+ o_bufchars(buf), o_buflines(buf), buf->docursor,buf->changepos);
+ bufappend(persbuf, toCHAR(line), 0);
+
+ /* maybe store the named marks */
+ if (calcelement(o_persist, toCHAR("marks")))
+ {
+ /* for each mark... */
+ for (i = 0; i < QTY(namedmark); i++)
+ {
+ /* skip if unset, or in a different buffer */
+ if (!namedmark[i] || markbuffer(namedmark[i]) != buf)
+ continue;
+
+ /* save it */
+ sprintf(line, "mark %c %ld\n",
+ 'a'+i, markoffset(namedmark[i]));
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+ }
+
+#ifdef FEATURE_REGION
+ /* maybe save regions */
+ if (calcelement(o_persist, toCHAR("regions")))
+ {
+ /* for each region in this buffer... */
+ for (region = buf->regions; region; region = region->next)
+ {
+ sprintf(line, "region %ld,%ld %s %s\n",
+ markline(region->from), markline(region->to)-1,
+ tochar8(colorinfo[(int)region->font].name),
+ tochar8(region->comment));
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+ }
+#endif
+
+#ifdef FEATURE_FOLD
+ /* maybe save folds */
+ if (calcelement(o_persist, toCHAR("folds")))
+ {
+ /* save each fold... */
+ for (fold = buf->fold; fold; fold = fold->next)
+ {
+ sprintf(line, "fold %ld,%ld %s\n",
+ markline(fold->from), markline(fold->to),
+ tochar8(fold->name));
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+
+ /* save each unfold... */
+ for (fold = buf->unfold; fold; fold = fold->next)
+ {
+ sprintf(line, "unfold %ld,%ld %s\n",
+ markline(fold->from), markline(fold->to),
+ tochar8(fold->name));
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+ }
+#endif
+}
+
+/* Append file-specific information from the old persistent file onto the
+ * end of the new persistent buffer. Skip information for buffers that we've
+ * just explicitly updated via persistbuf().
+ */
+static void persistother(buf, persbuf)
+ BUFFER buf; /* buffer to skip, or NULL to skip all current bufs */
+ BUFFER persbuf;/* where to append the file's contents */
+{
+ CHAR *line;
+ ELVBOOL skip;
+ long max;
+
+ /* try to open the file */
+ if (!ioopen(iofilename(tochar8(o_persistfile), '\0'), 'r', ElvFalse, ElvFalse, 't'))
+ {
+ return;
+ }
+
+ /* initially we'll skip. We don't want to copy the global info */
+ skip = ElvTrue;
+
+ /* fetch the limit, if any */
+ max = -1;
+ line = calcelement(o_persist, toCHAR("max"));
+ if (line && *line++ == ':')
+ {
+ for (max = 0; elvdigit(*line); line++)
+ max = max * 10 + *line - '0';
+ if (*line == 'k' || *line == 'K')
+ max <<= 10;
+ else if (*line == 'm' || *line == 'M')
+ max <<= 20;
+ }
+
+ /* for each line of the original persist file... */
+ while ((line = persistget()) != NULL)
+ {
+ /* is it "bufname" line? */
+ if (!CHARncmp(line, toCHAR("bufname "), 8))
+ {
+ /* if the buffer has reached its limit, then break */
+ if (max >= 0 && o_bufchars(persbuf) >= max)
+ break;
+
+ /* is it a buffer we want to skip? */
+ if (buf)
+ skip = (ELVBOOL)(!CHARcmp(line + 8, o_bufname(buf)));
+ else
+ {
+ for (skip = ElvFalse, buf = elvis_buffers;
+ !skip && buf;
+ buf = buf->next)
+ {
+ skip = (ELVBOOL)(!CHARcmp(line + 8, o_bufname(buf)));
+ }
+ buf = NULL;
+ }
+ }
+
+ /* MINOR BUG HERE!!! This can eat the blank line before
+ * "bufname" line.
+ */
+
+ /* if we want to skip, then skip */
+ if (skip)
+ continue;
+
+ /* append this line */
+ CHARcat(line, toCHAR("\n"));
+ bufappend(persbuf, line, 0);
+ }
+
+ /* close the file */
+ (void)ioclose();
+}
+
+/* save persistent information for a given buffer, or for all user buffers if
+ * buf==NULL.
+ */
+void bufpersistsave(buf)
+ BUFFER buf; /* buffer to be saved */
+{
+ BUFFER persbuf;
+ MARKBUF head, tail;
+ ELVBOOL oldhide;
+ static ELVBOOL savedall = ElvFalse;
+
+ /* if the persistfile option is unset, then do nothing */
+ if (!o_persistfile)
+ return;
+
+ /* if already saved all buffers, then don't save anything more. The
+ * "save all buffers" thing is only done during termination, before
+ * all of the individual buffers are freed.
+ */
+ if (savedall)
+ return;
+
+ /* if internal bffer, then don't do anything */
+ if (persistinternal(buf))
+ return;
+
+ /* create a new temporary buffer. We'll use this to construct a new
+ * version of the persfile.
+ */
+ persbuf = bufalloc(toCHAR(PERSIST_BUF), 0, ElvTrue);
+ if (o_bufchars(persbuf) > 0L)
+ {
+ bufreplace(marktmp(head, persbuf, 0L),
+ marktmp(tail, persbuf, o_bufchars(persbuf)),
+ NULL, 0L);
+ }
+
+ /* save histories */
+ persisthist("ex", ":", EX_BUF, persbuf);
+ persisthist("search", "/?", REGEXP_BUF, persbuf);
+
+ /* maybe save args */
+ if (calcelement(o_persist, toCHAR("args")))
+ {
+ char line[300];
+ int i;
+
+ for (i = 0; arglist[i]; i++)
+ {
+ sprintf(line, "arg %.294s\n", arglist[i]);
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+ sprintf(line, "argnext %d\n", argnext);
+ bufappend(persbuf, toCHAR(line), 0);
+ }
+
+ /* save either this buffer, or all buffers */
+ if (buf)
+ persistbuf(buf, persbuf);
+ else
+ {
+ /* scan through the list of buffers, and try to save them all */
+ for (buf = elvis_buffers; buf; buf = buf->next)
+ if (!persistinternal(buf))
+ persistbuf(buf, persbuf);
+ buf = NULL;
+ savedall = ElvTrue;
+ }
+
+ /* add any other info from the old persist file */
+ persistother(buf, persbuf);
+
+ /* save the persist info */
+ oldhide = msghide(ElvTrue);
+ bufwrite(marktmp(head, persbuf, 0),
+ marktmp(tail, persbuf, o_bufchars(persbuf)),
+ iofilename(tochar8(o_persistfile), '\0'), ElvTrue);
+ (void)msghide(ElvFalse);
+}
+#endif /* FEATURE_PERSIST */
+
/* Create a buffer with a given name. The buffer will initially be empty;
* if it is meant to be associated with a particular file, then the file must
* be copied into the buffer in a separate operation. If there is already
@@ -603,16 +1417,23 @@ BUFFER buffind(name)
* on the last character of the # expression, and the filename is returned.
* Otherwise it returns NULL and the scan variable is undefined.
*
- * This is used for expanding # in filenames.
+ * This is used for expanding % and # in filenames.
*/
-CHAR *buffilenumber(refp)
- CHAR **refp;
+CHAR *buffilenumber(curbuf, refp, endptr)
+ BUFFER curbuf; /* current buffer, used for % substitution */
+ CHAR **refp; /* reference to scanning variable */
+ CHAR **endptr; /* if non-NULL, store end pointer here */
{
long id;
BUFFER buf;
MARKBUF tmp;
+ ELVBOOL trim;
+ CHAR *name;
- assert(*refp && **refp == '#');
+ assert(*refp && (**refp == '#' || **refp == '%'));
+
+ /* for now, assume we keep the filename extension */
+ trim = ElvFalse;
/* remember which buf we're scanning, so we can fix *refp after NULL */
buf = markbuffer(scanmark(refp));
@@ -621,40 +1442,85 @@ CHAR *buffilenumber(refp)
/* the scanning context is in a buffer */
/* get the buffer number */
- for (id = 0; scannext(refp) && elvdigit(**refp); )
+ if (**refp == '%')
{
- id = id * 10 + **refp - '0';
+ id = -1;
+ scannext(refp);
}
+ else
+ for (id = 0; scannext(refp) && elvdigit(**refp); )
+ {
+ id = id * 10 + **refp - '0';
+ }
- /* move back one character, so *refp points to final char. This
- * can be tricky if we bumped into the end of the buffer.
- */
- if (*refp)
- (void)scanprev(refp);
+ /* if followed by '<' then we'll want to trim the extension */
+ if (*refp && **refp == '<')
+ trim = ElvTrue;
else
- (void)scanseek(refp, marktmp(tmp, buf, o_bufchars(buf) - 1));
+ {
+ /* move back one character, so *refp points to final
+ * char. This can be tricky if we bumped into the
+ * end of the buffer.
+ */
+ if (*refp)
+ (void)scanprev(refp);
+ else
+ (void)scanseek(refp, marktmp(tmp, buf, o_bufchars(buf) - 1));
+ }
}
else
{
/* The scanning context is in a string. */
/* get the buffer number */
- for (id = 0; elvdigit(*++*refp); )
+ if (**refp == '%')
{
- id = id * 10 + **refp - '0';
+ id = -1;
+ scannext(refp);
+ }
+ else
+ {
+ for (id = 0; elvdigit(*++*refp); )
+ {
+ id = id * 10 + **refp - '0';
+ }
}
- --*refp;
+ if (**refp == '<')
+ trim = ElvTrue;
+ else
+ --*refp;
}
- /* if 0, then use alternate file */
- if (id == 0)
- return o_previousfile;
+ /* convert id to a name */
+ if (id == -1)
+ /* use the current file */
+ name = o_filename(curbuf);
+ else if (id == 0)
+ /* use alternate file */
+ name = o_previousfile;
+ else
+ {
+ /* try to find a buffer with that value */
+ for (buf = elvis_buffers; buf && o_bufid(buf) != id; buf = buf->next)
+ {
+ }
+ name = buf ? o_filename(buf) : NULL;
+ }
+ if (!name)
+ return NULL;
- /* try to find a buffer with that value */
- for (buf = elvis_buffers; buf && o_bufid(buf) != id; buf = buf->next)
+ /* if necessary, trim the extension */
+ if (endptr)
{
+ *endptr = name + CHARlen(name);
+ if (trim)
+ {
+ while (*endptr != name && **endptr != '.')
+ (*endptr)--;
+ }
}
- return buf ? o_filename(buf) : NULL;
+
+ return name;
}
@@ -783,6 +1649,9 @@ BUFFER bufload(bufname, filename, reload)
void *locals;
# endif
#endif
+#ifdef FEATURE_PERSIST
+ ELVBOOL nopersist = ElvFalse; /* inhibit loading of persistent info? */
+#endif
#ifdef FEATURE_AUTOCMD
@@ -822,6 +1691,9 @@ BUFFER bufload(bufname, filename, reload)
else
bufwilldo(marktmp(top, buf, 0), ElvTrue);
bufreplace(marktmp(top, buf, 0), marktmp(end, buf, o_bufchars(buf)), (CHAR *)0, 0);
+#ifdef FEATURE_PERSIST
+ nopersist = ElvTrue;
+#endif
}
#ifdef FEATURE_REGION
@@ -1044,6 +1916,10 @@ BUFFER bufload(bufname, filename, reload)
/* set the initial cursor offset to 0 */
buf->docursor = 0L;
+#ifdef FEATURE_PERSIST
+ if (!nopersist)
+ persistload(buf);
+#endif
#ifdef FEATURE_AUTOCMD
/* done loading. Any later changes may generate Edit events */
@@ -1175,6 +2051,11 @@ void buffree(buffer)
}
#endif /* FEATURE_AUTOCMD */
+#ifdef FEATURE_PERSIST
+ /* save the persistent information */
+ bufpersistsave(buffer);
+#endif
+
/* transfer any marks to the dummy "bufdefopts" buffer */
while (buffer->marks)
{
@@ -2224,6 +3105,19 @@ void bufreplace(from, to, newp, newlen)
didmodify(markbuffer(from));
}
+/* Append text to a buffer. This is useful when constructing a buffer */
+void bufappend(buf, str, len)
+ BUFFER buf; /* buffer to receive the new text */
+ CHAR *str; /* the new text */
+ int len; /* length of the text, or 0 to use count it */
+{
+ MARKBUF tail;
+
+ if (len == 0)
+ len = CHARlen(str);
+ bufreplace(marktmp(tail, buf, o_bufchars(buf)), &tail, str, len);
+}
+
/* Copy part of one buffer into another. "dst" is the destination (where
* the pasted text will be inserted), and "from" and "to" describe the
* portion of the source buffer to insert.
View
7 buffer.h
@@ -143,7 +143,7 @@ extern MSGIMP bufmsgtype;
BEGIN_EXTERNC
extern void bufinit P_((void));
extern BUFFER bufalloc P_((CHAR *name, _BLKNO_ bufinfo, ELVBOOL internal));
-extern CHAR *buffilenumber P_((CHAR **refp));
+extern CHAR *buffilenumber P_((BUFFER curbuf, CHAR **refp, CHAR **endptr));
extern BUFFER buffind P_((CHAR *name));
extern BUFFER bufload P_((CHAR *bufname, char *filename, ELVBOOL reload));
extern BUFFER bufpath P_((CHAR *path, char *filename, CHAR *bufname));
@@ -152,4 +152,9 @@ extern ELVBOOL bufsave P_((BUFFER buf, ELVBOOL force, ELVBOOL mustwr));
extern void bufoptions P_((BUFFER buffer));
extern void buffree P_((BUFFER buffer));
extern void buftitle P_((BUFFER buffer, CHAR *title));
+extern void bufappend P_((BUFFER buf, CHAR *str, int len));
+#ifdef FEATURE_PERSIST
+extern void bufpersistinit P_((void));
+extern void bufpersistsave P_((BUFFER buf));
+#endif
END_EXTERNC
View
20 calc.c
@@ -4,7 +4,7 @@
#include "elvis.h"
#ifdef FEATURE_RCSID
-char id_calc[] = "$Id: calc.c,v 2.143 2003/10/18 04:47:18 steve Exp $";
+char id_calc[] = "$Id: calc.c,v 2.145 2004/03/14 23:18:52 steve Exp $";
#endif
#ifdef TRY
@@ -136,6 +136,9 @@ static CHAR *feature[] =
# ifdef FEATURE_NORMAL
toCHAR("normal"),
# endif
+# ifdef FEATURE_PERSIST
+ toCHAR("persist"),
+# endif
# ifdef FEATURE_PROTO
toCHAR("proto"),
# endif
@@ -2268,12 +2271,17 @@ CHAR *calculate(expr, arg, rule)
case '\\':
/* In most contexts, a backslash is treated as a
- * literal character. However, it can also be used to
- * quote the special characters of a message string:
- * dollar sign, parentheses, and the backslash itself.
+ * literal character; this works best in Windows names.
+ * However, it can also be used to quote the special
+ * characters of a message string: dollar sign,
+ * parentheses, and (except at the beginning of the
+ * line) the backslash itself. A \\ at the beginning
+ * of a line could be a Windows \\machine\dir\file name.
*/
expr++;
- if (build == result || !*expr || !strchr("$()\\", *expr))
+ if (!*expr
+ || (build == result && *expr == '\\')
+ || !strchr("$()", *expr))
{
/* at front of expression, or if followed by
* normal character - literal */
@@ -2727,7 +2735,7 @@ CHAR *calculate(expr, arg, rule)
if (base > 0)
{
Mismatch:
- msg(MSG_ERROR, "(\"()\") mismatch");
+ msg(MSG_ERROR, "\\(\\) mismatch");
return (CHAR *)0;
}
View
7 color.c
@@ -1014,7 +1014,6 @@ void colorsave(buf)
{
int i;
CHAR cmd[200];
- MARKBUF end;
guidot_t *scan;
/* for each color role... */
@@ -1035,8 +1034,7 @@ void colorsave(buf)
CHARcat(cmd, toCHAR("\n"));
/* append it to the buffer */
- (void)marktmp(end, buf, o_bufchars(buf));