readline scribblings; set GC alignment to 8-byte by default
svn: r8320
This commit is contained in:
parent
707416a13f
commit
62f38e2a40
|
@ -1,140 +0,0 @@
|
|||
|
||||
The _readline_ collection (not to be confused with MzScheme's
|
||||
`read-line' procedure) provides glue for using GNU's readline library
|
||||
with the MzScheme read-eval-print-loop.
|
||||
|
||||
|
||||
Normal use of readline
|
||||
----------------------
|
||||
|
||||
The _rep.ss_ library installs a readline-based input port, and hooks
|
||||
the prompt-and-read part of MzScheme's read-eval-print loop to
|
||||
interact with it.
|
||||
|
||||
You can start MzScheme with
|
||||
|
||||
mzscheme -L rep.ss readline
|
||||
|
||||
or you can put the following in your ~/.mzschemerc so that MzScheme
|
||||
starts with readline support when appropriate:
|
||||
|
||||
(when (regexp-match? #rx"xterm" (getenv "TERM"))
|
||||
(dynamic-require '(lib "rep.ss" "readline") #f))
|
||||
|
||||
The "rep.ss" module is actually a wrapper around "rep-start.ss", it
|
||||
will *not* invoke it if the input port is not a terminal port (eg,
|
||||
when the input is redirected from a file). Still the TERM condition
|
||||
above is useful for starting MzScheme in dumb terminals, eg, inside
|
||||
Emacs.
|
||||
|
||||
Completion is set to use the visible bindings in the current
|
||||
namespace; this is far from ideal, but it's better than readline's
|
||||
default filename completion which is rarely useful. In addition, the
|
||||
readline history is stored across invocations in MzScheme's
|
||||
preferences file, assuming MzScheme exits normally.
|
||||
|
||||
|
||||
Interacting with the readline-enabled input port
|
||||
------------------------------------------------
|
||||
|
||||
The _pread.ss_ library provides customization, and support for
|
||||
prompt-reading after "rep.ss" installs the new input port.
|
||||
|
||||
The reading facility that the new input port provides can be
|
||||
customized with these parameters:
|
||||
|
||||
> currnet-prompt
|
||||
The prompt that is used, as a byte string. Defaults to #"> ".
|
||||
|
||||
> show-all-prompts
|
||||
If #f, no prompt is shown until you write input that is completely
|
||||
readable. For example, when you type
|
||||
(foo bar) (+ 1
|
||||
2)
|
||||
you will see a single prompt in the beginning.
|
||||
|
||||
The problem is that the first expression can be `(read-line)' which
|
||||
normally consumes the rest of the text on the *same* line. The
|
||||
default value of this parameter is therefore #t, making it mimic
|
||||
plain I/O interactions.
|
||||
|
||||
> max-history
|
||||
The number of history entries to save. Defaults to 100.
|
||||
|
||||
> keep-duplicates
|
||||
If this is #f (the default), then lines that are equal to the
|
||||
previous one are not added as new history items.
|
||||
|
||||
> keep-blanks
|
||||
If #f (the default), blank input lines are not kept in history.
|
||||
|
||||
The new input port that you get when you require "rep.ss" is a custom
|
||||
port that uses readline for all inputs. The problem is when you want
|
||||
to display a prompt and then read some input: readline will get
|
||||
confused if it's not used when the cursor is at the beginning of the
|
||||
line, which is why it has a `prompt' argument. To use this prompt:
|
||||
|
||||
(parameterize ([readline-prompt some-byte-string])
|
||||
...code-that-reads...)
|
||||
|
||||
This will make the first call to readline use the prompt, and
|
||||
subsequent calls will use an all-spaces prompt of the same length (for
|
||||
example, when you're reading an s-expression). The normal value of
|
||||
`readline-prompt' is #f for an empty prompt (and 'spaces after the
|
||||
prompt is used, which is why you should use `parameterize' to restore
|
||||
it to #f).
|
||||
|
||||
A proper solution would be to install a custom output port too which
|
||||
keeps track of text that is displayed without a trailing newline. As
|
||||
a cheaper solution, if line-counting is enabled for the terminal's
|
||||
output-port, then a newline is printed before reading if the column is
|
||||
not 0. ("rep.ss" enables line-counting for the output port.)
|
||||
|
||||
|
||||
Warning
|
||||
-------
|
||||
|
||||
The readline library uses the output port directly. You should not
|
||||
use it when `current-input-port' has been modified, or when it was not
|
||||
a terminal port when MzScheme was started (eg, when reading input from
|
||||
a pipe). Expect problems if you ignore this warning (not too bad,
|
||||
mostly problems with detecting an EOF).
|
||||
|
||||
|
||||
Direct bindings for readline hackers
|
||||
------------------------------------
|
||||
|
||||
The _readline.ss_ library provides these functions:
|
||||
|
||||
> (readline prompt-string)
|
||||
prints the given prompt string and reads a line
|
||||
|
||||
> (readline-bytes prompt-bytes)
|
||||
same as above, but using raw byte-strings for the prompt and
|
||||
returning a byte string
|
||||
|
||||
> (add-history s)
|
||||
adds the given string to the readline history, which is accessible
|
||||
to the user via the up-arrow key
|
||||
|
||||
> (add-history-bytes s)
|
||||
adds the given byte string to the readline history, which is
|
||||
accessible to the user via the up-arrow key
|
||||
|
||||
> (set-completion-function! proc [type])
|
||||
sets readline's `rl_completion_entry_function' function according to
|
||||
proc, which is expected to be a `string -> (list-of string/bytes)'
|
||||
procedure; the `type' argument defaults to `_string' but you can use
|
||||
it with `_bytes' instead to have your function receive a byte
|
||||
string.
|
||||
|
||||
|
||||
License Issues
|
||||
--------------
|
||||
|
||||
GNU's readline library is covered by the GPL, and that applies to code
|
||||
that links with it. PLT Scheme is LGPL, so this code is not used by
|
||||
default -- you should explicitly enable it if you want to. Also, be
|
||||
aware that if you write code that uses this library, it will make your
|
||||
code link to the readline library when invoked -- with the usual GPL
|
||||
implications.
|
|
@ -2,6 +2,7 @@
|
|||
(module info setup/infotab
|
||||
(define doc.txt "doc.txt")
|
||||
(define name "readline")
|
||||
(define scribblings '(("readline.scrbl")))
|
||||
(define blurb
|
||||
`("The readline collection provides glue for using GNU's readline library"
|
||||
" with the MzScheme read-eval-print-loop.")))
|
||||
|
|
185
collects/readline/readline.scrbl
Normal file
185
collects/readline/readline.scrbl
Normal file
|
@ -0,0 +1,185 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
(for-label scheme/base
|
||||
readline/pread
|
||||
readline/readline))
|
||||
|
||||
@(define readline "Readline")
|
||||
@(define Readline "Readline")
|
||||
|
||||
@title{@bold{Readline}: Terminal Interaction}
|
||||
|
||||
The @filepath{readline} collection (not to be confused with MzScheme's
|
||||
@scheme[read-line] function) provides glue for using GNU's @|readline|
|
||||
library with the MzScheme @scheme[read-eval-print-loop].
|
||||
|
||||
@section{Normal Use of @|Readline|}
|
||||
|
||||
@defmodule*[(readline/rep readline/rep-start)]
|
||||
|
||||
The @schememodname[readline/rep] library installs a @|readline|-based
|
||||
input port, and hooks the prompt-and-read part of MzScheme's
|
||||
@scheme[read-eval-print-loop] to interact with it
|
||||
|
||||
You can start MzScheme with
|
||||
|
||||
@commandline{mzscheme -il readline/rep}
|
||||
|
||||
or you can put the following in your @filepath{~/.mzschemerc} so that
|
||||
MzScheme starts with @|readline| support when appropriate:
|
||||
|
||||
@schemeblock[
|
||||
(when (regexp-match? #rx"xterm"
|
||||
(getenv "TERM"))
|
||||
(dynamic-require 'readline/rep #f))
|
||||
]
|
||||
|
||||
The @schememodname[readline/rep] module is actually a wrapper around
|
||||
@schememodname[readline/rep-start]; it will @emph{not} invoke
|
||||
@schememodname[readline/rep-start] if the input port is not a terminal
|
||||
port (e.g., when the input is redirected from a file); see
|
||||
@scheme[terminal-port?]. Still, the @envvar{TERM} condition
|
||||
above is useful for starting MzScheme in dumb terminals (e.g., inside
|
||||
Emacs.)
|
||||
|
||||
Completion is set to use the visible bindings in the current
|
||||
namespace; this is far from ideal, but it's better than @|readline|'s
|
||||
default filename completion which is rarely useful. In addition, the
|
||||
@|readline| history is stored across invocations in MzScheme's
|
||||
preferences file, assuming that MzScheme exits normally.
|
||||
|
||||
|
||||
@section{Interacting with the @|Readline|-Enabled Input Port }
|
||||
|
||||
@defmodule[readline/pread]{ The @schememodname[readline/pread] library
|
||||
provides customization, and support for prompt-reading after
|
||||
@schememodname[readline/rep] installs the new input port.}
|
||||
|
||||
The reading facility that the new input port provides can be
|
||||
customized with the following parameters.
|
||||
|
||||
|
||||
@defparam[current-prompt bstr bytes?]{
|
||||
|
||||
A parameter that determines the prompt that is used, as a byte string.
|
||||
Defaults to @scheme[#"> "].}
|
||||
|
||||
|
||||
@defboolparam[show-all-prompts on?]{
|
||||
|
||||
A parameter. If @scheme[#f], no prompt is shown until you write input
|
||||
that is completely readable. For example, when you type
|
||||
|
||||
@schemeblock[
|
||||
(foo bar) (+ 1
|
||||
2)
|
||||
]
|
||||
|
||||
you will see a single prompt in the beginning.
|
||||
|
||||
The problem is that the first expression can be @scheme[(read-line)],
|
||||
which normally consumes the rest of the text on the @emph{same} line.
|
||||
The default value of this parameter is therefore @scheme[#t], making
|
||||
it mimic plain I/O interactions.}
|
||||
|
||||
|
||||
@defparam[max-history n nonnegative-exact-integer?]{
|
||||
|
||||
A parameter that determines the number of history entries to save,
|
||||
defaults to @scheme[100].}
|
||||
|
||||
|
||||
@defboolparam[keep-duplicates keep?]{
|
||||
|
||||
A parameter. If @scheme[#f] (the default), then lines that are equal
|
||||
to the previous one are not added as new history items.}
|
||||
|
||||
|
||||
@defboolparam[keep-blanks keep?]{
|
||||
|
||||
A parameter. If @scheme[#f] (the default), blank input lines are not
|
||||
kept in history.}
|
||||
|
||||
|
||||
@defparam[readline-prompt status (or/c false/c bytes? (one-of/c 'space))]{
|
||||
|
||||
The new input port that you get when you require
|
||||
@schememodname[readline/rep] is a custom port that uses @|readline| for
|
||||
all inputs. The problem is when you want to display a prompt and then
|
||||
read some input, @|readline| will get confused if it is not used when the
|
||||
cursor is at the beginning of the line (which is why it has a
|
||||
@scheme[_prompt] argument.) To use this prompt:
|
||||
|
||||
@schemeblock[
|
||||
(parameterize ([readline-prompt some-byte-string])
|
||||
...code-that-reads...)
|
||||
]
|
||||
|
||||
This expression makes the first call to @|readline| use the prompt, and
|
||||
subsequent calls will use an all-spaces prompt of the same length (for
|
||||
example, when you're reading an S-expression). The normal value of
|
||||
@scheme[readline-prompt] is @scheme[#f] for an empty prompt (and
|
||||
spaces after the prompt is used, which is why you should use
|
||||
@scheme[parameterize] to restore it to @scheme[#f]).
|
||||
|
||||
A proper solution would be to install a custom output port, too, which
|
||||
keeps track of text that is displayed without a trailing newline. As
|
||||
a cheaper solution, if line-counting is enabled for the terminal's
|
||||
output-port, then a newline is printed before reading if the column is
|
||||
not 0. (The @schememodname[readline/rep] library enables line-counting
|
||||
for the output port.)
|
||||
|
||||
@bold{Warning:} The @|readline| library uses the output port directly.
|
||||
You should not use it when @scheme[current-input-port] has been
|
||||
modified, or when it was not a terminal port when MzScheme was started
|
||||
(eg, when reading input from a pipe). Expect some problems if you
|
||||
ignore this warning (not too bad, mostly problems with detecting an
|
||||
EOF).}
|
||||
|
||||
|
||||
|
||||
@section{Direct Bindings for @|Readline| Hackers}
|
||||
|
||||
@defmodule[readline/readline]
|
||||
|
||||
@defproc[(readline [prompt string?]) string?]{
|
||||
|
||||
Prints the given prompt string and reads a line.}
|
||||
|
||||
|
||||
@defproc[(readline-bytes [prompt bytes?]) bytes?]{
|
||||
|
||||
Like @scheme[readline], but using raw byte-strings for the prompt and
|
||||
returning a byte string.}
|
||||
|
||||
|
||||
@defproc[(add-history [str string?]) void?]{
|
||||
|
||||
Adds the given string to the @|readline| history, which is accessible to
|
||||
the user via the up-arrow key.}
|
||||
|
||||
|
||||
@defproc[(add-history-bytes [str string?]) void?]{
|
||||
|
||||
Adds the given byte string to the @|readline| history, which is
|
||||
accessible to the user via the up-arrow key.}
|
||||
|
||||
|
||||
@defproc[(set-completion-function! [proc ((or/c string? bytes?)
|
||||
. -> . (listof (or/c string? bytes?)))]
|
||||
[type (one-of/c 'string 'bytes) 'string])
|
||||
void?]{
|
||||
|
||||
Sets @|readline|'s @tt{rl_completion_entry_function} to
|
||||
@scheme[proc]. The @scheme[type] argument determines the type of value
|
||||
upplied to the @scheme[proc].}
|
||||
|
||||
|
||||
@section{License Issues}
|
||||
|
||||
GNU's @|readline| library is covered by the GPL, and that applies to code
|
||||
that links with it. PLT Scheme is LGPL, so this code is not used by
|
||||
default; you should explicitly enable it if you want to. Also, be
|
||||
aware that if you write code that uses this library, it will make your
|
||||
code link to the @|readline| library when invoked, with the usual GPL
|
||||
implications.
|
|
@ -57,7 +57,11 @@ by @scheme[kind], which must be one of the following:
|
|||
@item{@indexed-scheme['temp-dir] --- the standard directory for
|
||||
storing temporary files. Under @|AllUnix|, this is the directory
|
||||
specified by the @indexed-envvar{TMPDIR} environment variable, if it
|
||||
is defined.}
|
||||
is defined, otherwise it is the first path that exists among
|
||||
@filepath{/var/tmp}, @filepath{/usr/tmp}, and @filepath{/tmp}. Under
|
||||
Windows, the result is the directory specified by the
|
||||
@indexed-envvar{TMP} or @indexed-envvar{TEMP} environment variable,
|
||||
if it is defined, otherwise it is the current directory.}
|
||||
|
||||
@item{@indexed-scheme['init-dir] --- the directory containing the
|
||||
initialization file used by stand-alone @exec{mzscheme} executable.
|
||||
|
|
|
@ -42,7 +42,21 @@
|
|||
#endif
|
||||
|
||||
#if defined(sparc) || defined(__sparc) || defined(__sparc__)
|
||||
# define ALIGN_DOUBLES
|
||||
/* Required for `double' operations: */
|
||||
# define GC_ALIGN_EIGHT
|
||||
#endif
|
||||
|
||||
/* Even when 8-byte alginment is not required by the processor, it's
|
||||
better for floating-point performance (PowerPC) and may be required
|
||||
for some libraries (VecLib in Mac OS X, including x86).
|
||||
|
||||
Under Windows, Mac OS X, and Linux x86_64, malloc() returns 16-byte
|
||||
aligned data. And, actually, VecLib says that it requires
|
||||
16-byte-aligned data. So, in those cases, GC_ALIGN_SIXTEEN might be
|
||||
better --- but that's a lot more expensive, increasing DrScheme's
|
||||
initial footprint by almost 10%. */
|
||||
#ifndef GC_ALIGN_EIGHT
|
||||
# define GC_ALIGN_EIGHT
|
||||
#endif
|
||||
|
||||
#include "msgprint.c"
|
||||
|
@ -229,14 +243,24 @@ struct mpage {
|
|||
void **backtrace;
|
||||
};
|
||||
|
||||
#ifdef ALIGN_DOUBLES
|
||||
/* Make sure alloction starts out double-word aligned: */
|
||||
# define PREFIX_SIZE WORD_SIZE
|
||||
# define PREFIX_WSIZE 1
|
||||
/* Make sure alloction starts out double-word aligned.
|
||||
The header on each allocated object is one word, so to make
|
||||
the content double-word aligned, we deeper. */
|
||||
#ifdef GC_ALIGN_SIXTEEN
|
||||
# ifdef SIXTY_FOUR_BIT_INTEGERS
|
||||
# define PREFIX_WSIZE 1
|
||||
# else
|
||||
# define PREFIX_WSIZE 3
|
||||
# endif
|
||||
#else
|
||||
# define PREFIX_SIZE 0
|
||||
# define PREFIX_WSIZE 0
|
||||
# if defined(GC_ALIGN_EIGHT) && !defined(SIXTY_FOUR_BIT_INTEGERS)
|
||||
# define PREFIX_WSIZE 1
|
||||
# else
|
||||
# define PREFIX_WSIZE 0
|
||||
# endif
|
||||
#endif
|
||||
#define PREFIX_SIZE (PREFIX_WSIZE * WORD_SIZE)
|
||||
|
||||
|
||||
/* this is the maximum size of an object that will fit on a page, in words.
|
||||
the "- 3" is basically used as a fudge/safety factor, and has no real,
|
||||
|
@ -441,12 +465,35 @@ static void *allocate_big(size_t sizeb, int type)
|
|||
return PTR(NUM(addr) + PREFIX_SIZE + WORD_SIZE);
|
||||
}
|
||||
|
||||
#ifdef ALIGN_DOUBLES
|
||||
# define ALIGN_SIZE(sizew) (((sizew) & 0x1) ? ((sizew) + 1) : (sizew))
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (((sizeb) & WORD_SIZE) ? ((sizeb) + WORD_SIZE) : (sizeb))
|
||||
/* ALIGN_BYTES_SIZE can assume that the argument is already word-aligned. */
|
||||
/* INSET_WORDS is how many words in a tagged array can be padding, plus one; it
|
||||
must also be no more than the minimum size of a tagged element. */
|
||||
#ifdef GC_ALIGN_SIXTEEN
|
||||
# ifdef SIXTY_FOUR_BIT_INTEGERS
|
||||
# define ALIGN_SIZE(sizew) (((sizew) & 0x1) ? ((sizew) + 1) : (sizew))
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (((sizeb) & WORD_SIZE) ? ((sizeb) + WORD_SIZE) : (sizeb))
|
||||
# define INSET_WORDS 1
|
||||
# else
|
||||
# define ALIGN_SIZE(sizew) (((sizew) & 0x3) ? ((sizew) + (4 - ((sizew) & 0x3))) : (sizew))
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (((sizeb) & (3 * WORD_SIZE)) ? ((sizeb) + ((4 * WORD_SIZE) - ((sizeb) & (3 * WORD_SIZE)))) : (sizeb))
|
||||
# define INSET_WORDS 3
|
||||
# endif
|
||||
#else
|
||||
# define ALIGN_SIZE(sizew) (sizew)
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (sizeb)
|
||||
# ifdef GC_ALIGN_EIGHT
|
||||
# ifdef SIXTY_FOUR_BIT_INTEGERS
|
||||
# define ALIGN_SIZE(sizew) (sizew)
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (sizeb)
|
||||
# define INSET_WORDS 0
|
||||
# else
|
||||
# define ALIGN_SIZE(sizew) (((sizew) & 0x1) ? ((sizew) + 1) : (sizew))
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (((sizeb) & WORD_SIZE) ? ((sizeb) + WORD_SIZE) : (sizeb))
|
||||
# define INSET_WORDS 1
|
||||
# endif
|
||||
# else
|
||||
# define ALIGN_SIZE(sizew) (sizew)
|
||||
# define ALIGN_BYTES_SIZE(sizeb) (sizeb)
|
||||
# define INSET_WORDS 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
inline static void *allocate(size_t sizeb, int type)
|
||||
|
@ -901,7 +948,7 @@ static void *get_backtrace(struct mpage *page, void *ptr)
|
|||
unsigned long delta;
|
||||
|
||||
if (page->big_page)
|
||||
ptr = PTR(page->addr + PREFIX_SIZE);
|
||||
ptr = PTR(page->addr + PREFIX_SIZE + WORD_SIZE);
|
||||
|
||||
delta = PPTR(ptr) - PPTR(page->addr);
|
||||
return page->backtrace[delta - 1];
|
||||
|
@ -1690,7 +1737,7 @@ inline static void mark_normal_obj(struct mpage *page, void *ptr)
|
|||
case PAGE_TARRAY: {
|
||||
struct objhead *info = (struct objhead *)((char*)ptr - WORD_SIZE);
|
||||
unsigned short tag = *(unsigned short*)ptr;
|
||||
void **temp = ptr, **end = PPTR(info) + (info->size - 1);
|
||||
void **temp = ptr, **end = PPTR(info) + (info->size - INSET_WORDS);
|
||||
|
||||
while(temp < end) temp += mark_table[tag](temp);
|
||||
break;
|
||||
|
@ -1718,7 +1765,7 @@ inline static void mark_acc_big_page(struct mpage *page)
|
|||
case PAGE_XTAGGED: GC_mark_xtagged(start); break;
|
||||
case PAGE_TARRAY: {
|
||||
unsigned short tag = *(unsigned short *)start;
|
||||
end -= 1;
|
||||
end -= INSET_WORDS;
|
||||
while(start < end) start += mark_table[tag](start);
|
||||
break;
|
||||
}
|
||||
|
@ -2295,7 +2342,7 @@ inline static void internal_mark(void *p)
|
|||
case PAGE_XTAGGED: GC_mark_xtagged(start); break;
|
||||
case PAGE_TARRAY: {
|
||||
unsigned short tag = *(unsigned short *)start;
|
||||
end -= 1;
|
||||
end -= INSET_WORDS;
|
||||
while(start < end) start += mark_table[tag](start);
|
||||
break;
|
||||
}
|
||||
|
@ -2316,7 +2363,7 @@ inline static void internal_mark(void *p)
|
|||
}
|
||||
case PAGE_TARRAY: {
|
||||
void **start = p;
|
||||
void **end = PPTR(info) + (info->size - 1);
|
||||
void **end = PPTR(info) + (info->size - INSET_WORDS);
|
||||
unsigned short tag = *(unsigned short *)start;
|
||||
while(start < end) start += mark_table[tag](start);
|
||||
break;
|
||||
|
@ -2798,7 +2845,7 @@ static void repair_heap(void)
|
|||
break;
|
||||
case PAGE_TARRAY: {
|
||||
unsigned short tag = *(unsigned short *)start;
|
||||
end -= 1;
|
||||
end -= INSET_WORDS;
|
||||
while(start < end) start += fixup_table[tag](start);
|
||||
break;
|
||||
}
|
||||
|
@ -2851,7 +2898,7 @@ static void repair_heap(void)
|
|||
struct objhead *info = (struct objhead *)start;
|
||||
size_t size = info->size;
|
||||
if(info->mark) {
|
||||
void **tempend = (start++) + (size - 1);
|
||||
void **tempend = (start++) + (size - INSET_WORDS);
|
||||
unsigned short tag = *(unsigned short*)start;
|
||||
while(start < tempend)
|
||||
start += fixup_table[tag](start);
|
||||
|
|
Loading…
Reference in New Issue
Block a user