90 lines
3.0 KiB
Scheme
90 lines
3.0 KiB
Scheme
(define-module (uniseg graphemes)
|
|
#:use-module (uniseg graphemes stream)
|
|
#:use-module (uniseg graphemes iterator)
|
|
#:use-module (ice-9 hash-table)
|
|
#:use-module (ice-9 streams)
|
|
#:use-module (srfi srfi-41)
|
|
#:use-module (srfi srfi-1)
|
|
#:use-module (srfi srfi-9 gnu)
|
|
#:export (make-grapheme
|
|
grapheme?
|
|
grapheme-width
|
|
grapheme-delta-width
|
|
grapheme-modification?
|
|
grapheme-glyphs
|
|
grapheme-glyphs-reverse
|
|
grapheme-state
|
|
grapheme-string
|
|
string->grapheme
|
|
string->grapheme-list
|
|
char->grapheme))
|
|
|
|
(define-immutable-record-type <grapheme>
|
|
(_make-grapheme width delta-width modification? state glyphs-reverse glyphs-promise string-promise)
|
|
grapheme?
|
|
(width grapheme-width)
|
|
(delta-width grapheme-delta-width)
|
|
(modification? grapheme-modification?)
|
|
(state grapheme-state)
|
|
(glyphs-reverse grapheme-glyphs-reverse)
|
|
(glyphs-promise _grapheme-glyphs-promise)
|
|
(string-promise _grapheme-string-promise))
|
|
|
|
(define (make-grapheme width delta modification? state glyphs-reverse)
|
|
(_make-grapheme
|
|
width
|
|
delta
|
|
modification?
|
|
state
|
|
glyphs-reverse
|
|
(delay (reverse glyphs-reverse))
|
|
(delay (reverse-list->string glyphs-reverse))))
|
|
|
|
(define (grapheme-glyphs grapheme)
|
|
"Return a lazily-constructed list of glyphs in the grapheme"
|
|
(force (_grapheme-glyphs-promise grapheme)))
|
|
|
|
(define (grapheme-string grapheme)
|
|
"Return a lazily-constructed string of the glyphs in the grapheme."
|
|
(force (_grapheme-string-promise grapheme)))
|
|
|
|
(define (string->grapheme-list str)
|
|
"Get a list of all the final graphemes (not including intermediates) in the provided string"
|
|
(define stream (string->grapheme-stream str))
|
|
(let loop ((stream stream))
|
|
(define grapheme (stream-car stream))
|
|
(define next-stream (stream-cdr stream))
|
|
(define have-next? (stream-pair? next-stream))
|
|
(define next-modification?
|
|
(and have-next?
|
|
(grapheme-modification? (stream-car next-stream))))
|
|
|
|
(cond
|
|
(next-modification? (loop next-stream))
|
|
(have-next? (cons grapheme (loop next-stream)))
|
|
(else (list grapheme)))))
|
|
|
|
(define (string->grapheme str)
|
|
"Reads from `str' until we reach the end of the first grapheme cluster"
|
|
(define stream (string->grapheme-stream str))
|
|
(define first-grapheme (stream-car stream))
|
|
|
|
;; Skip first, we want to get the last entry that is a modification
|
|
;; (or the first entry, if there are no mods afterwards)
|
|
(define last-grapheme
|
|
(let loop ((stream stream))
|
|
(define grapheme (stream-car stream))
|
|
(define next-stream (stream-cdr stream))
|
|
(if (and (stream-pair? next-stream)
|
|
(grapheme-modification? (stream-car next-stream)))
|
|
(loop next-stream)
|
|
grapheme)))
|
|
|
|
(if (grapheme-modification? last-grapheme)
|
|
last-grapheme
|
|
first-grapheme))
|
|
|
|
(define (char->grapheme char)
|
|
"Attempt to convert a char to a grapheme. Returns #f if no valid grapheme is formed from the single character."
|
|
((make-grapheme-iterator) char))
|