/collects/mred/private/wxme/wordbreak.rkt

http://github.com/gmarceau/PLT · Racket · 155 lines · 140 code · 15 blank · 0 comment · 38 complexity · d300b46fc723e6f359a7ceb83a0f3154 MD5 · raw file

  1. #lang scheme/base
  2. (require scheme/class
  3. "../syntax.rkt"
  4. "cycle.rkt")
  5. (provide editor-wordbreak-map%
  6. the-editor-wordbreak-map
  7. standard-wordbreak)
  8. (defclass editor-wordbreak-map% object%
  9. (define char-map (make-hash))
  10. (super-new)
  11. (hash-set! char-map #\- '(line))
  12. (def/public (set-map [char? ch] [(make-list (symbol-in caret line selection user1 user2)) mask])
  13. (hash-set! char-map ch mask))
  14. (def/public (get-map [char? ch])
  15. (or (hash-ref char-map ch #f)
  16. (cond
  17. [(or (char-alphabetic? ch)
  18. (char-numeric? ch))
  19. '(caret line selection)]
  20. [(not (char-whitespace? ch))
  21. '(line)]
  22. [else null]))))
  23. (define the-editor-wordbreak-map (new editor-wordbreak-map%))
  24. (define MAX-DIST-TRY 30)
  25. (define wb-get-map (generic editor-wordbreak-map% get-map))
  26. (define (string-ref* str n)
  27. (if (n . >= . (string-length str))
  28. #\nul
  29. (string-ref str n)))
  30. (define/top (standard-wordbreak [text% win]
  31. [(make-or-false (make-box exact-nonnegative-integer?)) startp]
  32. [(make-or-false (make-box exact-nonnegative-integer?)) endp]
  33. [(symbol-in caret line selection user1 user2) reason])
  34. (let ([wb (send win get-wordbreak-map)])
  35. (when wb
  36. (with-method ([get-map (wb get-map)])
  37. (define (nonbreak? ch) (memq reason (get-map ch)))
  38. (when startp
  39. (let* ([start (unbox startp)]
  40. [pstart start]
  41. [lstart (send win find-newline 'backward start 0)]
  42. [lstart (if lstart
  43. (if (eq? 'caret reason)
  44. (or (and (positive? lstart)
  45. (send win find-newline 'backward (sub1 lstart) 0))
  46. 0)
  47. lstart)
  48. 0)]
  49. [lend (min (+ start 1) (send win last-position))]
  50. [tstart (if ((- start lstart) . > . MAX-DIST-TRY)
  51. (- start MAX-DIST-TRY)
  52. lstart)]
  53. [text (send win get-text tstart lend)]
  54. [start (- start tstart)]
  55. [pstart (- pstart tstart)])
  56. (let ploop ([phase1-complete? #f]
  57. [phase2-complete? #f]
  58. [start start]
  59. [pstart pstart]
  60. [text text]
  61. [tstart tstart])
  62. (let*-values ([(start phase1-complete?)
  63. (if phase1-complete?
  64. (values start #t)
  65. (let ([start (if (and (positive? start)
  66. (nonbreak? (string-ref* text start)))
  67. (sub1 start)
  68. start)])
  69. (values start
  70. (not (nonbreak? (string-ref* text start))))))]
  71. [(start phase2-complete?)
  72. (if (not (eq? 'selection reason))
  73. (if (not phase2-complete?)
  74. (let loop ([start start])
  75. (if (and (positive? start)
  76. (not (nonbreak? (string-ref* text start))))
  77. (loop (sub1 start))
  78. (if (nonbreak? (string-ref* text start))
  79. (values start #t)
  80. (values start #f))))
  81. (values start #t))
  82. (values start phase2-complete?))])
  83. (let loop ([start start])
  84. (if (and (positive? start)
  85. (nonbreak? (string-ref* text start)))
  86. (loop (sub1 start))
  87. (let ([start (if (and (start . < . pstart)
  88. (not (nonbreak? (string-ref* text start))))
  89. (add1 start)
  90. start)])
  91. (if (and (zero? start)
  92. (not (= lstart tstart)))
  93. (ploop phase1-complete?
  94. phase2-complete?
  95. (+ start (- tstart lstart))
  96. (+ pstart (- tstart lstart))
  97. (send win get-text lstart lend)
  98. lstart)
  99. (set-box! startp (+ start tstart))))))))))
  100. (when endp
  101. (let* ([end (unbox endp)]
  102. [lstart end]
  103. [lend (send win find-newline 'forward end)]
  104. [lend (if lend
  105. (if (eq? 'caret reason)
  106. (or (send win find-newline 'forward (+ lend 1))
  107. (send win last-position))
  108. lend)
  109. (send win last-position))]
  110. [tend (if ((- lend end) . > . MAX-DIST-TRY)
  111. (+ end MAX-DIST-TRY)
  112. lend)]
  113. [text (send win get-text lstart tend)]
  114. [end (- end lstart)]
  115. [lend (- lend lstart)]
  116. [tend (- tend lstart)])
  117. (let ploop ([phase1-complete? #f]
  118. [text text]
  119. [tend tend]
  120. [end end])
  121. (let-values ([(end phase1-complete?)
  122. (if phase1-complete?
  123. (values end #t)
  124. (let loop ([end end])
  125. (if (and (end . < . tend)
  126. (not (nonbreak? (string-ref* text end))))
  127. (loop (add1 end))
  128. (if (end . < . tend)
  129. (values end #t)
  130. (values end #f)))))])
  131. (let loop ([end end])
  132. (if (and (end . < . tend)
  133. (nonbreak? (string-ref* text end)))
  134. (loop (add1 end))
  135. (if (and (= tend end) (not (= lend tend)))
  136. (ploop phase1-complete?
  137. (send win get-text lstart (+ lstart lend))
  138. lend
  139. end)
  140. (set-box! endp (+ end lstart)))))))))))))