I'm interested in using
racket/gui for an application that needs a rich text editor. I'm interested in general in any existing work along these lines, but I have a very basic question to start with: How can I get structured data from an editor with styled text?
To be concrete, imagine a tiny subset of HTML:
(flat-rec-contract xexpr/c string? (cons/c 'b (listof xexpr/c)) (cons/c 'i (listof xexpr/c)) (cons/c 'span (listof xexpr/c)))
Thanks to Markdown View using the Racket editor%, I know how to display such an
xexpr/c in a
#lang racket/gui (define (insert-html ed x) (dynamic-wind (λ () (send ed begin-edit-sequence)) (λ () (define s-l (send ed get-style-list)) (define plain-style (send s-l find-named-style (send ed default-style-name))) (define bold-style (send s-l find-or-create-style plain-style (make-object style-delta% 'change-bold))) (define italic-style (send s-l find-or-create-style plain-style (make-object style-delta% 'change-style 'italic))) (define bold-italic-style (send s-l find-or-create-join-style bold-style italic-style)) (let loop ([modes #hasheq()] [x x]) (match x [(cons 'span xs) (for ([x (in-list xs)]) (loop modes x))] [(cons 'b xs) (for ([x (in-list xs)]) (loop (hash-set modes 'b #t) x))] [(cons 'i xs) (for ([x (in-list xs)]) (loop (hash-set modes 'i #t) x))] [(? string?) (define start (send ed last-position)) (send ed insert x) (define end (send ed last-position)) (send ed change-style (match (hash-keys modes 'ordered) ['(b i) bold-italic-style] ['(b) bold-style] ['(i) italic-style] ['() plain-style]) start end)]))) (λ () (send ed end-edit-sequence)))) (define txt (new text% [auto-wrap #t])) (insert-html txt `(span "This is some text with " (b "bold " (i "and italic")) " parts. It also has " (i "italic " (b "and bold")) " parts.")) (define f (new frame% [label "Rich text%"] [width 400] [height 400])) (define ec (new editor-canvas% [parent f] [style '(no-hscroll)] [editor txt])) (send f show #t)
Similarly, I can imagine how to add buttons and menu items so the user can edit text and styling in the usual way.
What I don't know is how to get the contents of an editor like
txt as an
xexpr/c. I know there are various methods like
snip%, but I'm not clear on how
change-style interacts with creating/splitting/joining snips, or if there's some better approach overall.