Sunday, 8 January 2012

Exercise 152: More text editing...


Note: These are my answers as I originally created them. As I have moved on to questions 153 and 154  I have discovered that some of my tests are simply wrong. I've left them incorrect here as this was how  I originally answered them and they aren't actually being as part of this answer. You will need to read the posts for questions 153 and 154 to see my (corrected) answers!!!

Explain why the template for editor-kh deals with "\t" and "\r"  before it checks for strings of length 1.

Strings of length 1 (ie, ordinary typed characters) need to be simply inserted into the text. ; Any special characters (eg tabs, backspaces) need to take an appropriate special action (eg deleting text, adding a carriage return etc).

The issue is that "\b", "\r" etc are only one charater long eg:

> (string-length "\b")
 1

 So, we need to check for and handle these special characters first, and only then handle any other ordinary single characters;



; code supplied by the text book
(define (editor-kh ed k)
  (cond
    [(key=? k "left") (editor-lft ed)]
    [(key=? k "right") (editor-rgt ed)]
    [(key=? k "\b") (editor-del ed)]
    [(key=? k "\t") ed]
    [(key=? k "\r") ed]
    [(= (string-length k) 1) (editor-ins ed k)]
    [else ed]))


; dummy functions
(define (editor-lft ed) 1)
(define (editor-rgt ed) 1)
(define (editor-del ed) 1)


(define (editor-ins ed k)
  (make-editor (cons k (editor-pre ed)) (editor-post ed)))



; test function for editor-ins. Empty editor should let you
; insert text at the front of the pre element
(check-expect
  (editor-ins (make-editor empty empty) "e")
  (make-editor (cons "e" empty) empty))


; test function for editor-ins. Text should be inserted before
; any existing text. Remember that the letters in 'pre' are
; stored in reverse order, so if we want to append text, 
; we need to append it to the start. 
; This apparently makes the design easier, but they
; haven't clarified why this should be ... (yet)
(check-expect
  (editor-ins (make-editor (cons "d" empty)
                           (cons "f" (cons "g" empty)))
              "e")
  (make-editor (cons "e" (cons "d" empty))
               (cons "f" (cons "g" empty))))


Anything below here is from 151.scm and is included cause we need these chunks of code - these aren't part of the answers to this question. Comments have been removed - if you're curious, go and read the post for question 151!

; Lo1s -> Lo1s
; produce a reverse version of the given list
 (check-expect
 (rev (cons "a" (cons "b" (cons "c" empty))))
  (cons "c" (cons "b" (cons "a" empty))))

(define (rev l)
  (cond ((empty? l) l)
        ((cons? l) (add-to-end (first l) 
                               (rev (rest l)))))) 


; adds an item to the end of the given list
; I didn't read this section of the manual as I wanted to come up 
; with this on my own. 
; I had issues at this point as I kept wanting to use 'cons' to join the two
; lists together - this of course results in a nested list (which is not what
; we want. eg;
; (cons (list "a" "b") (cons "a" empty)) => (list (list "a" "b") "a")
; After I discovered the 'append' function, this function shrank away to almost
; nothing. The only reason we need it now, is to save creating the second
; list with item and empty in the main function.
(define (add-to-end item l)
   (append l (cons item empty)
  ))


(check-expect (add-to-end "a" empty) (list "a"))
(check-expect (add-to-end "c" (list "a" "b")) (list "a" "b" "c"))






; An Editor is (make-editor Lo1S Lo1S)
; An Lo1S is one of:
; – empty
; – (cons 1String Lo1S)
(define-struct editor (pre post))


; This function consumes two strings and produces an Editor.
(define (create-editor left-string right-string)
  (make-editor (explode left-string) (explode right-string)))


; These values are given directly by the question 
; constants
(define HEIGHT 20) ; the height of the editor
(define WIDTH 200) ; its width
(define FTSZ 11) ; the font size
(define FTCL "black") ; the font color

; graphical constants - also supplied directly by the question
(define MT (empty-scene WIDTH HEIGHT))
(define CU (rectangle 1 HEIGHT "solid" "red"))


; Editor -> Image
; render an editor as an image of the two texts separated by the cursor
; (supplied directly from the question)
(define (editor-render e)
  MT)



; main : String -> Editor
; launch the editor given some initial string
; (supplied directly from the question)
(define (main s)
   (big-bang (create-editor s "")
             (on-key editor-kh)
             (to-draw editor-render)))


; At this point we can actually call our editor, but it doesn't
; do anything interesting yet. (Or anything at all really!)
;(make-editor (make-editor "Hello" "World") "")


; The first two test statements are supplied by the question.
; This first checks to make sure that when you press 'e' you
; create an editor displaying e
(check-expect (editor-kh (create-editor "" "") "e")
              (create-editor "e" ""))


; This checks that when you type 'e', it's added at the cursor point
; (rather than the beginning or end of the editor)
(check-expect (editor-kh (create-editor "cd" "fg") "e") 
              (create-editor "ecd" "fg"))