gtk-screen: Crude face support using pango-layout-set-markup.
authorMatt Birkholz <matt@birkholz.chandler.az.us>
Mon, 11 Feb 2013 22:50:11 +0000 (15:50 -0700)
committerMatt Birkholz <matt@birkholz.chandler.az.us>
Mon, 11 Feb 2013 22:50:11 +0000 (15:50 -0700)
src/gtk-screen/gtk-faces.scm [new file with mode: 0644]
src/gtk-screen/gtk-screen.pkg
src/gtk-screen/gtk-screen.scm

diff --git a/src/gtk-screen/gtk-faces.scm b/src/gtk-screen/gtk-faces.scm
new file mode 100644 (file)
index 0000000..a41eff1
--- /dev/null
@@ -0,0 +1,173 @@
+#| -*-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 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.
+
+|#
+
+;;;; Support for the FACE text property.
+;;; package: (edwin screen gtk-screen)
+
+(define-command add-text-property
+  "Adds a text property to the current region."
+  (lambda ()
+    (let* ((key (prompt-for-expression "Key"))
+          (val (prompt-for-expression "Value")))
+      (list key val (current-region))))
+  (lambda (key val region)
+    (add-text-property (mark-group (region-start region))
+                      (mark-index (region-start region))
+                      (mark-index (region-end region))
+                      key val)))
+
+(define-structure markup-context
+  image image-index image-end
+  column tab-width char-image-strings)
+
+(define (markup-add-char! context char)
+  ;; Does NOT increment column.
+  (let ((image-index (markup-context-image-index context))
+       (image-end (markup-context-image-end context)))
+    (if (fix:< image-index image-end)
+       (let ((image (markup-context-image context)))
+         (string-set! image image-index char)
+         (set-markup-context-image-index! context (fix:1+ image-index))))))
+
+(define (markup-add-string! context string)
+  ;; Does NOT increment column.
+  (let ((image-index (markup-context-image-index context))
+       (image-end (markup-context-image-end context)))
+    (if (fix:< image-index image-end)
+       (let ((image (markup-context-image context))
+             (nchars (fix:min (string-length string)
+                              (fix:- image-end image-index))))
+         (substring-move! string 0 nchars image image-index)
+         (set-markup-context-image-index! context
+                                          (fix:+ image-index nchars))))))
+
+(define (markup-image-char! context char)
+  ;; DOES increment column and escape CHAR.
+  (let ((escape (case char
+                 ((#\<) "&lt;")
+                 ((#\&) "&amp;")
+                 (else #f))))
+    (if escape
+       (markup-add-string! context escape)
+       (markup-add-char! context char)))
+  (set-markup-context-column! context (fix:1+ (markup-context-column context))))
+
+(define (markup-image-string! context string)
+  ;; DOES increment column and escape characters.
+  (let ((end (string-length string)))
+    (let loop ((i 0))
+      (if (fix:< i end)
+         (begin
+           (markup-image-char! context (string-ref string i))
+           (loop (fix:1+ i)))))))
+
+(define (gtk-group-line-image! group start end
+                              image image-start image-end
+                              tab-width column-offset char-image-strings
+                              receiver)
+  ;; Like GROUP-LINE-IMAGE!, but includes Pango markup.  RECEIVER will
+  ;; be called with the start of the next line or END, and the number
+  ;; of characters of markup generated.
+  (let* ((context (make-markup-context image image-start image-end
+                                      column-offset
+                                      tab-width char-image-strings))
+        (index (markup-line! group start end context)))
+    (receiver index (markup-context-image-index context))))
+
+(define (markup-line! group start end context)
+
+  (define-syntax define-integrable-operator
+    (rsc-macro-transformer
+     (lambda (form environment)
+       (declare (ignore environment))
+       (if (syntax-match? '((IDENTIFIER . MIT-BVL) + FORM) (cdr form))
+          `(BEGIN
+            (DECLARE (INTEGRATE-OPERATOR ,(caadr form)))
+            (DEFINE ,@(cdr form)))
+          (ill-formed-syntax form)))))
+
+  (define-integrable-operator (start-face! face)
+    (if face (markup-add-string! context (face-markup face))))
+
+  (define-integrable-operator (stop-face! face)
+    (if face (markup-add-string! context "</span>")))
+
+  (define-integrable-operator (image-char! char)
+    (let ((char-image (vector-ref (markup-context-char-image-strings context)
+                                 (char->integer char))))
+      (if char-image
+         (markup-image-string! context char-image)
+         (markup-image-char! context char))))
+
+  (define-integrable (image-tab!)
+    (let ((tab-width (markup-context-tab-width context))
+         (column (markup-context-column context)))
+      (let ((n (fix:- tab-width (fix:remainder column tab-width))))
+       (let tab-loop ((i 0))
+         (if (fix:< i n)
+             (begin
+               (markup-image-char! context #\space)
+               (tab-loop (fix:1+ i))))))))
+
+  (define-integrable (overflow?)
+    (not (fix:< (markup-context-image-index context)
+               (markup-context-image-end context))))
+
+  (let loop ((index start) (face #f))
+    (cond ((overflow?)
+          index)
+         ((fix:= index end)
+          (stop-face! face)
+          end)
+         ((get-text-property group index 'INVISIBLE #f)
+          (let ((next (next-specific-property-change group index end
+                                                     'INVISIBLE)))
+            (if next
+                (loop next face)
+                (begin
+                  (stop-face! face)
+                  end))))
+         (else
+          (let ((char (group-right-char group index)))
+            (cond ((char=? char #\newline)
+                   (stop-face! face)
+                   (fix:1+ index))
+                  ((char=? char #\tab)
+                   (image-tab!)
+                   (loop (fix:1+ index) face))
+                  (else
+                   (let ((face* (get-text-property group index 'FACE #f)))
+                     (if (not (eq? face* face))
+                         (begin
+                           (stop-face! face)
+                           (start-face! face*)))
+                     (image-char! char)
+                     (loop (fix:1+ index) face*)))))))))
+
+(define (face-markup face)
+  (if (string? face)
+      (string-append "<span "face">")
+      "<span>"))
\ No newline at end of file
index 40b392957091c7f15bd1df32083d07cdcedf0b97..5553ca097fcbd0cd8472f28707d866f6ce90d9aa 100644 (file)
@@ -29,7 +29,7 @@ USA.
 (global-definitions "../edwin/edwin")
 
 (define-package (edwin screen gtk-screen)
-  (files "gtk-screen")
+  (files "gtk-screen" "gtk-faces")
   (parent (edwin screen))
   (export ()
          set-gtk-screen-hooks!)
@@ -148,6 +148,7 @@ USA.
          pango-layout-get-pixel-extents
          pango-layout-index-to-pos
          pango-layout-set-text
+         pango-layout-set-markup
 
          pango-context-get-metrics
          pango-context-spacing
index edd9224f14d25be9b30a11e09f9c1c5d2a09493f..d958a19c2fe73d2e5bab60b460d1b8e80d131e4a 100644 (file)
@@ -2139,7 +2139,7 @@ USA.
         (max-image-size (fix:-1+ image-buffer-size)))
     ;; Image the whole paragraph into a max-sized image-buffer.
     (set-string-length! image-buffer image-buffer-size)
-    (group-line-image!
+    (gtk-group-line-image!
      group (line-ink-start-index line) (group-display-end-index group)
      image-buffer 0 max-image-size
      (buffer-drawing-tab-width drawing)
@@ -2151,8 +2151,11 @@ USA.
        (set-mark-index! (line-ink-end line) text-index)
 
        ;; Run Pango on buffer.
-       (set-string-length! image-buffer image-index)
-       (pango-layout-set-text pango-layout image-buffer)))))
+       (if (fix:> image-index 0)
+          (begin
+            (set-string-length! image-buffer image-index)
+            (pango-layout-set-markup pango-layout image-buffer))
+          (pango-layout-set-text pango-layout ""))))))
 
 (define (final-newline? group)
   (let ((index (group-display-end-index group)))