Skip to content

Commit

Permalink
Remove {beginning end}-of-line; somewhat optimize paragraph numbers
Browse files Browse the repository at this point in the history
From racket/expeditor#10 it sounds like the
"traditional" approach isn't desirable after all; remove it.

Make the paragraph numbering "moderately" optimized: On do-udpate! we
invalidate it, and then the paragraph methods recalculate it
on-demand.

This is a mid point on design spectrum between "naively scan from 0
every single time" and "do some minimal rebuild on every update".

Note that I'm not 100% confident about the concurrency safety. But I'm
committing anyway, for now, because I plan to take hard look at
concurrency for the class, soon, including this as well as the
potential for update generations arriving on command threads out of
order and needing to be queued something like TCP packets.
  • Loading branch information
greghendershott committed May 23, 2022
1 parent 128edc7 commit 31455e7
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 88 deletions.
101 changes: 45 additions & 56 deletions racket/hash-lang.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
(thread consume-update-chan)

(define/public (do-update! gen pos old-len new-str)
(invalidate-paragraph-info)
(set! generation gen)
(set! updated-thru pos)
(set! str
Expand Down Expand Up @@ -271,6 +272,34 @@
(get-tokens gen end upto proc))]
[_ '()]))

;;; Paragraph/position info

;; do-update! calls invalidate-paragraph-info; the textoid
;; paragraph methods call validate-paragraph-info. In other words,
;; we don't attempt to efficiently update it; we throw it away and
;; rebuild if/as/when needed.
(define position-paragraphs #f)
(define paragraph-starts #f)
(define/private (invalidate-paragraph-info)
(set! position-paragraphs #f)
(set! paragraph-starts #f))
(define/public (validate-paragraph-info)
(unless (and position-paragraphs paragraph-starts)
(define-values (p-p p-s)
(let loop ([pos 0] [para 0] [pos-para #hasheqv()] [para-pos #hasheqv((0 . 0))])
(cond
[(= pos (string-length str))
(values (hash-set pos-para pos para) para-pos)]
[(char=? #\newline (string-ref str pos))
(loop (add1 pos) (add1 para)
(hash-set pos-para pos para)
(hash-set para-pos (add1 para) (add1 pos)))]
[else
(loop (add1 pos) para (hash-set pos-para pos para) para-pos)])))
(set! position-paragraphs p-p)
(set! paragraph-starts p-s)))


;;; Something for Emacs forward-sexp-function etc.

(define/public (grouping gen pos dir limit count)
Expand Down Expand Up @@ -326,12 +355,6 @@
(string-ref str pos)
#\nul))

;; ;; I think this is needed by at-exp determine-spaces.
;; (define/public (find-up-sexp pos)
;; (if (< pos (string-length str))
;; (add1 pos) ;; FIXME
;; #f))

(define/public (get-text from upto)
(substring str from upto))

Expand Down Expand Up @@ -365,56 +388,22 @@
(define/public (get-backward-navigation-limit pos)
0)

;; Note: Not attempting to maintain a data structure in do-update!
;; for paragraphs; just calculating on-demand from start position.

(define/public (position-paragraph desired-pos [eol? #f])
(let loop ([pos 0] [para 0])
(cond [(= pos desired-pos) para]
[(= pos (string-length str)) para]
[(char=? #\newline (string-ref str pos))
(loop (add1 pos) (add1 para))]
[else
(loop (add1 pos) para)])))

(define/public (paragraph-start-position desired-para)
(let loop ([pos 0] [para 0])
(cond [(= para desired-para) pos]
[(= pos (string-length str))
(error 'paragraph-start-position "lookup failed: ~e" desired-para)]
[(char=? #\newline (string-ref str pos))
(loop (add1 pos) (add1 para))]
[else
(loop (add1 pos) para)])))

(define/public (paragraph-end-position desired-para)
(let loop ([pos 0] [para -1])
(cond [(= para desired-para) (sub1 pos)]
[(= pos (string-length str)) pos]
[(char=? #\newline (string-ref str pos))
(loop (add1 pos) (add1 para))]
[else
(loop (add1 pos) para)])))

;; These next two methods are a faster, simpler alternative to the
;; "paragraphs" methods, for use by indenters. These aren't
;; currently part of textoid<%> but I'm proposing to add them.

(define/public (beginning-of-line pos)
(define len (string-length str))
(let loop ([pos pos])
(cond [(<= pos 0) 0]
[(<= len pos) (loop (sub1 len))]
[(char=? #\newline (string-ref str (sub1 pos))) pos]
[else (loop (sub1 pos))])))

(define/public (end-of-line pos)
(define len (string-length str))
(let loop ([pos pos])
(cond [(< pos 0) (loop 0)]
[(<= len pos) (sub1 len)] ;implicit at end
[(char=? #\newline (string-ref str pos)) pos]
[else (loop (add1 pos))])))
(define/public (position-paragraph pos [eol? #f])
(validate-paragraph-info)
(or (hash-ref position-paragraphs pos #f)
(error 'position-paragraph "lookup failed: ~e" pos)))

(define/public (paragraph-start-position para)
(validate-paragraph-info)
(or (hash-ref paragraph-starts para #f)
(error 'paragraph-start-position "lookup failed: ~e" para)))

(define/public (paragraph-end-position para)
(validate-paragraph-info)
(define n (hash-ref paragraph-starts (add1 para) #f))
(if n
(sub1 n)
(last-position)))

(define/public (backward-match pos cutoff)
(backward-matching-search pos cutoff 'one))
Expand Down
33 changes: 1 addition & 32 deletions test/racket/hash-lang-test.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -459,35 +459,4 @@

(check-string (call/input-url (string->url "https://raw.githubusercontent.com/mflatt/shrubbery-rhombus-0/master/demo.rkt") get-pure-port port->string)
#:check-motion? #f ;large file & we already test motion above
#:check-indent? #t)

(let ()
(define o (test-create "0\n234\n6\n8\n\n"))
(check-equal? (send o beginning-of-line 0) 0)
(check-equal? (send o beginning-of-line 1) 0)
(check-equal? (send o beginning-of-line 2) 2)
(check-equal? (send o beginning-of-line 3) 2)
(check-equal? (send o beginning-of-line 4) 2)
(check-equal? (send o beginning-of-line 5) 2)
(check-equal? (send o beginning-of-line 6) 6)
(check-equal? (send o beginning-of-line 7) 6)
(check-equal? (send o beginning-of-line 8) 8)
(check-equal? (send o beginning-of-line 9) 8)
(check-equal? (send o beginning-of-line 10) 10)
(check-equal? (send o beginning-of-line 11) 10)
(check-equal? (send o beginning-of-line 1000) 10)
(check-equal? (send o end-of-line -1) 1)
(check-equal? (send o end-of-line 0) 1)
(check-equal? (send o end-of-line 1) 1)
(check-equal? (send o end-of-line 2) 5)
(check-equal? (send o end-of-line 3) 5)
(check-equal? (send o end-of-line 4) 5)
(check-equal? (send o end-of-line 5) 5)
(check-equal? (send o end-of-line 6) 7)
(check-equal? (send o end-of-line 7) 7)
(check-equal? (send o end-of-line 8) 9)
(check-equal? (send o end-of-line 9) 9)
(check-equal? (send o end-of-line 10) 10)
(check-equal? (send o end-of-line 11) 10)
(check-equal? (send o end-of-line 1000) 10))
)
#:check-indent? #t))

0 comments on commit 31455e7

Please sign in to comment.