scratch/edwin/image.scm

415 lines
14 KiB
Scheme
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#| -*-Scheme-*-
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017, 2018, 2019, 2020 Massachusetts Institute of Technology
This file is part of MIT/GNU Scheme.
MIT/GNU Scheme is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
MIT/GNU Scheme is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with MIT/GNU Scheme; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
USA.
|#
;;;; Display Imaging
(define (group-columns group start end column tab-width char-image-strings)
(let ((text (group-text group))
(gap-start (group-gap-start group))
(gap-end (group-gap-end group))
(gap-length (group-gap-length group)))
(cond ((fix:<= end gap-start)
(substring-columns text start end column
tab-width char-image-strings))
((fix:<= gap-start start)
(substring-columns text
(fix:+ start gap-length)
(fix:+ end gap-length)
column
tab-width
char-image-strings))
(else
(substring-columns text
gap-end
(fix:+ end gap-length)
(substring-columns text start gap-start
column tab-width
char-image-strings)
tab-width
char-image-strings)))))
(define (string-columns string column tab-width char-image-strings)
(substring-columns string 0 (string-length string) column tab-width
char-image-strings))
(define (substring-columns string start end column tab-width
char-image-strings)
(if tab-width
(do ((index start (fix:+ index 1))
(column column
(fix:+ column
(let ((char (string-ref string index)))
(if (char=? char #\tab)
(fix:- tab-width
(fix:remainder column tab-width))
(string-length
(vector-ref char-image-strings
(char->integer char))))))))
((fix:= index end) column))
(do ((index start (fix:+ index 1))
(column column
(fix:+ column
(string-length
(vector-ref char-image-strings
(char->integer
(string-ref string index)))))))
((fix:= index end) column))))
(define default-char-image-strings/original-emacs
(let ((strings (make-vector 256)))
(do ((i #x00 (+ i 1)))
((= #x20 i))
(vector-set! strings i (string #\^ (integer->char (+ #x40 i)))))
(do ((i #x20 (+ i 1)))
((= #x7f i))
(vector-set! strings i (string (integer->char i))))
(vector-set! strings #x7f "^?")
(do ((i #x80 (+ i 1)))
((= #x100 i))
(vector-set! strings i (string-append "\\" (number->string i 8))))
strings))
(define default-char-image-strings/iso-8859-1
(let ((strings (vector-copy default-char-image-strings/original-emacs)))
(do ((i #xA0 (+ i 1)))
((= #x100 i))
(vector-set! strings i (string (integer->char i))))
strings))
(define default-char-image-strings/windows-1252
(let ((strings (vector-copy default-char-image-strings/iso-8859-1)))
(define (fixup i) (vector-set! strings i (string (integer->char i))))
(fixup #x80) ;Euro
(do ((i #x82 (+ i 1))) ((= i #x8d)) (fixup i))
(fixup #x8e) ;Z with hacek
(do ((i #x91 (+ i 1))) ((= i #x9d)) (fixup i))
(fixup #x9e) ;z with hacek
(fixup #x9f) ;Y with diaeresis
strings))
(define default-char-image-strings/ascii
(let ((strings (vector-copy default-char-image-strings/original-emacs)))
(subvector-move-left!
'#("[NUL]" "[SOH]" "[STX]" "[ETX]" "[EOT]" "[ENQ]" "[ACK]" "[BEL]"
"[BS]" "[HT]" "[NL]" "[VT]" "[FF]" "[CR]" "[SO]" "[SI]"
"[DLE]" "[DC1]" "[DC2]" "[DC3]" "[DC4]" "[NAK]" "[SYN]" "[ETB]"
"[CAN]" "[EM]" "[SUB]" "[ESC]" "[FS]" "[GS]" "[RS]" "[US]")
0 #x20 strings 0)
strings))
(define default-char-image-strings default-char-image-strings/iso-8859-1)
(define (group-line-columns group start end column
tab-width char-image-strings)
;; Like GROUP-COLUMNS, but stops at line end.
(let ((text (group-text group))
(gap-start (group-gap-start group))
(gap-end (group-gap-end group))
(gap-length (group-gap-length group)))
(cond ((fix:<= end gap-start)
(substring-line-columns text start end column
tab-width char-image-strings))
((fix:<= gap-start start)
(let ((i&c
(substring-line-columns text
(fix:+ start gap-length)
(fix:+ end gap-length)
column
tab-width
char-image-strings)))
(cons (fix:- (car i&c) gap-length) (cdr i&c))))
(else
(let ((i&c
(substring-line-columns text start gap-start
column tab-width
char-image-strings)))
(if (fix:< (car i&c) gap-start)
i&c
(let ((i&c
(substring-line-columns text
gap-end
(fix:+ end gap-length)
(cdr i&c)
tab-width
char-image-strings)))
(cons (fix:- (car i&c) gap-length) (cdr i&c)))))))))
(define (string-line-columns string column tab-width char-image-strings)
(substring-line-columns string 0 (string-length string) column tab-width
char-image-strings))
(define (substring-line-columns string start end column tab-width
char-image-strings)
(if tab-width
(let loop ((index start) (column column))
(if (fix:= index end)
(cons index column)
(let ((char (string-ref string index)))
(if (char=? char #\newline)
(cons index column)
(loop (fix:+ index 1)
(fix:+ column
(if (char=? char #\tab)
(fix:- tab-width
(fix:remainder column tab-width))
(string-length
(vector-ref char-image-strings
(char->integer char))))))))))
(let loop ((index start) (column column))
(if (fix:= index end)
(cons index column)
(let ((char (string-ref string index)))
(if (char=? char #\newline)
(cons index column)
(loop (fix:+ index 1)
(fix:+ column
(string-length
(vector-ref char-image-strings
(char->integer char)))))))))))
(define (group-column->index group start end start-column column tab-width
char-image-strings)
(let ((text (group-text group))
(gap-start (group-gap-start group))
(gap-end (group-gap-end group))
(gap-length (group-gap-length group)))
(cond ((fix:<= end gap-start)
(substring-column->index text start end start-column column
tab-width char-image-strings))
((fix:<= gap-start start)
(let ((result
(substring-column->index text
(fix:+ start gap-length)
(fix:+ end gap-length)
start-column
column
tab-width
char-image-strings)))
(vector-set! result 0 (fix:- (vector-ref result 0) gap-length))
result))
(else
(let ((result
(substring-column->index text start gap-start
start-column column tab-width
char-image-strings)))
(if (and (fix:< (vector-ref result 1) column)
(fix:= (vector-ref result 0) gap-start))
(let ((result
(substring-column->index text
gap-end
(fix:+ end gap-length)
(fix:+ (vector-ref result 1)
(vector-ref result 2))
column
tab-width
char-image-strings)))
(vector-set! result 0
(fix:- (vector-ref result 0) gap-length))
result)
result))))))
(define (substring-column->index string start end start-column column
tab-width char-image-strings)
;; If COLUMN falls in the middle of a multi-column character, the
;; index returned is that of the character. Thinking of the index
;; as a pointer between characters, the value is the pointer to the
;; left of the multi-column character. Only if COLUMN reaches
;; across the character will the right-hand pointer be returned.
;; Various things depend on this.
(if tab-width
(let loop ((index start) (c start-column))
(if (or (fix:= c column)
(fix:= index end)
(char=? #\newline (string-ref string index)))
(vector index c 0)
(let ((c
(fix:+ c
(let ((char (string-ref string index)))
(if (char=? char #\tab)
(fix:- tab-width (fix:remainder c tab-width))
(string-length
(vector-ref char-image-strings
(char->integer char))))))))
(if (fix:> c column)
(vector index column (fix:- c column))
(loop (fix:+ index 1) c)))))
(let loop ((index start) (c start-column))
(if (or (fix:= c column)
(fix:= index end)
(char=? #\newline (string-ref string index)))
(vector index c 0)
(let ((c
(fix:+ c
(string-length
(vector-ref char-image-strings
(char->integer
(string-ref string index)))))))
(if (fix:> c column)
(vector index column (fix:- c column))
(loop (fix:+ index 1) c)))))))
(define (substring-image! string string-start string-end
image image-start image-end
tab-width column-offset results
char-image-strings)
(let loop ((string-index string-start) (image-index image-start))
(if (or (fix:= image-index image-end)
(fix:= string-index string-end))
(begin
(vector-set! results 0 string-index)
(vector-set! results 1 image-index)
(vector-set! results 2 0))
(let ((char (string-ref string string-index))
(partial
(lambda (partial)
(vector-set! results 0 string-index)
(vector-set! results 1 image-end)
(vector-set! results 2 partial))))
(if (and (char=? char #\tab) tab-width)
(let ((n
(fix:- tab-width
(fix:remainder (fix:+ column-offset
image-index)
tab-width))))
(let ((end (fix:+ image-index n)))
(if (fix:<= end image-end)
(begin
(do ((image-index image-index
(fix:+ image-index 1)))
((fix:= image-index end))
(string-set! image image-index #\space))
(loop (fix:+ string-index 1) end))
(begin
(do ((image-index image-index
(fix:+ image-index 1)))
((fix:= image-index image-end))
(string-set! image image-index #\space))
(partial (fix:- end image-end))))))
(let* ((image-string (vector-ref char-image-strings
(char->integer char)))
(image-len (string-length image-string)))
(string-set! image image-index (string-ref image-string 0))
(if (fix:= image-len 1)
(loop (fix:+ string-index 1) (fix:+ image-index 1))
(if (fix:< (fix:+ image-index image-len) image-end)
(let copy-image-loop ((i 1))
(string-set! image (fix:+ image-index i)
(string-ref image-string i))
(if (fix:= (fix:+ i 1) image-len)
(loop (fix:+ string-index 1)
(fix:+ image-index image-len))
(copy-image-loop (fix:+ i 1))))
(let copy-image-loop ((i 1))
(cond ((fix:= i image-len)
(loop (fix:+ string-index 1)
(fix:+ image-index image-len)))
((fix:= (fix:+ image-index i) image-end)
(partial (fix:- image-len i)))
(else
(string-set! image (fix:+ image-index i)
(string-ref image-string i))
(copy-image-loop (fix:+ i 1)))))))))))))
(define (string-image string start-column tab-width char-image-strings)
(substring-image string 0 (string-length string) start-column tab-width
char-image-strings))
(define (substring-image string start end start-column tab-width
char-image-strings)
(let ((columns
(fix:- (substring-columns string start end start-column tab-width
char-image-strings)
start-column)))
(let ((image (make-string columns)))
(substring-image! string start end
image 0 columns
tab-width start-column substring-image-results
char-image-strings)
image)))
(define substring-image-results
(make-vector 3))
(define (group-image! group start end
image image-start image-end
tab-width column-offset results
char-image-strings)
(let ((text (group-text group))
(gap-start (group-gap-start group))
(gap-end (group-gap-end group))
(gap-length (group-gap-length group)))
(cond ((fix:<= end gap-start)
(substring-image! text start end
image image-start image-end
tab-width column-offset results
char-image-strings))
((fix:<= gap-start start)
(substring-image! text
(fix:+ start gap-length) (fix:+ end gap-length)
image image-start image-end
tab-width column-offset results
char-image-strings)
(vector-set! results 0 (fix:- (vector-ref results 0) gap-length)))
(else
(substring-image! text start gap-start
image image-start image-end
tab-width column-offset results
char-image-strings)
(if (fix:< (vector-ref results 1) image-end)
(begin
(substring-image! text gap-end (fix:+ end gap-length)
image (vector-ref results 1) image-end
tab-width column-offset results
char-image-strings)
(vector-set! results 0
(fix:- (vector-ref results 0) gap-length))))))))
(define (partial-image! char n image image-start image-end tab-width
char-image-strings)
;; Assume that (< IMAGE-START IMAGE-END) and that N is less than the
;; total width of the image for the character.
(let ((ascii (char->integer char)))
(if (and (fix:= ascii (char->integer #\tab)) tab-width)
(let ((end
(let ((end (fix:+ image-start n)))
(if (fix:< end image-end) end image-end))))
(do ((image-index image-start (fix:+ image-index 1)))
((fix:= image-index end))
(string-set! image image-index #\space)))
(let ((picture (vector-ref char-image-strings ascii)))
(let ((end
(let ((end (fix:+ image-start n)))
(if (fix:< end image-end) end image-end))))
(string-set! image image-start (string-ref picture 1))
(let loop ((i (fix:- (string-length picture) n))
(image-index image-start))
(if (fix:< image-index end)
(begin
(string-set! image image-index (string-ref picture i))
(loop (fix:+ i 1) (fix:+ image-index 1))))))))))