Give windows each their own top/point/mark marks. Basic window split/close/switch commands.
This commit is contained in:
parent
a512da0d7b
commit
1cdf0900b6
|
@ -1,6 +1,6 @@
|
||||||
Make it reloadable
|
Make it reloadable
|
||||||
|
|
||||||
Windows need their own top-of-window-mtype and point location
|
The status line isn't cleared away when you C-x 2.
|
||||||
|
|
||||||
Preserve column on up/down better. This includes dealing with tab expansion
|
Preserve column on up/down better. This includes dealing with tab expansion
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
(require "buffer.rkt")
|
(require "buffer.rkt")
|
||||||
(require "keys.rkt")
|
(require "keys.rkt")
|
||||||
(require "rope.rkt")
|
(require "rope.rkt")
|
||||||
|
(require "window.rkt")
|
||||||
|
|
||||||
(provide (all-from-out "mode.rkt"
|
(provide (all-from-out "mode.rkt"
|
||||||
"editor.rkt"
|
"editor.rkt"
|
||||||
"buffer.rkt"
|
"buffer.rkt"
|
||||||
"keys.rkt"
|
"keys.rkt"
|
||||||
"rope.rkt"))
|
"rope.rkt"
|
||||||
|
"window.rkt"))
|
||||||
|
|
195
rmacs/buffer.rkt
195
rmacs/buffer.rkt
|
@ -1,8 +1,8 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(provide make-buffergroup
|
(provide (struct-out buffer-mark-type)
|
||||||
|
make-buffergroup
|
||||||
initialize-buffergroup!
|
initialize-buffergroup!
|
||||||
main-mark-type
|
|
||||||
buffer?
|
buffer?
|
||||||
make-buffer
|
make-buffer
|
||||||
register-buffer!
|
register-buffer!
|
||||||
|
@ -13,7 +13,6 @@
|
||||||
buffer-reorder!
|
buffer-reorder!
|
||||||
buffer-next
|
buffer-next
|
||||||
buffer-prev
|
buffer-prev
|
||||||
buffer-pos
|
|
||||||
buffer-title
|
buffer-title
|
||||||
buffer-rope
|
buffer-rope
|
||||||
buffer-group
|
buffer-group
|
||||||
|
@ -25,21 +24,23 @@
|
||||||
buffer-remove-mode!
|
buffer-remove-mode!
|
||||||
buffer-toggle-mode!
|
buffer-toggle-mode!
|
||||||
buffer-size
|
buffer-size
|
||||||
buffer-move-to!
|
|
||||||
buffer-move-by!
|
|
||||||
buffer-start-of-line
|
buffer-start-of-line
|
||||||
buffer-end-of-line
|
buffer-end-of-line
|
||||||
buffer-move-to-start-of-line!
|
buffer-mark-types
|
||||||
buffer-move-to-end-of-line!
|
buffer-mark*
|
||||||
|
buffer-mark
|
||||||
|
buffer-mark-pos*
|
||||||
|
buffer-mark-pos
|
||||||
buffer-mark!
|
buffer-mark!
|
||||||
buffer-clear-mark!
|
buffer-clear-mark!
|
||||||
buffer-mark-pos
|
buffer-move-mark!
|
||||||
|
buffer-move-mark-to-start-of-line!
|
||||||
|
buffer-move-mark-to-end-of-line!
|
||||||
buffer-region-split
|
buffer-region-split
|
||||||
buffer-region
|
buffer-region
|
||||||
buffer-region-update!
|
buffer-region-update!
|
||||||
buffer-insert!
|
buffer-insert!
|
||||||
buffer-replace-contents!
|
buffer-replace-contents!
|
||||||
call-with-excursion
|
|
||||||
buffer-search
|
buffer-search
|
||||||
buffer-findf
|
buffer-findf
|
||||||
|
|
||||||
|
@ -67,14 +68,16 @@
|
||||||
(require "mode.rkt")
|
(require "mode.rkt")
|
||||||
(require "keys.rkt")
|
(require "keys.rkt")
|
||||||
|
|
||||||
(define main-mark-type (mark-type "main" 'right))
|
(struct buffer-mark-type (kind ;; Symbol
|
||||||
|
window-id ;; Symbol
|
||||||
|
preserve? ;; Boolean
|
||||||
|
) #:prefab)
|
||||||
|
|
||||||
(struct buffergroup ([members #:mutable] ;; (CircularList Buffer)
|
(struct buffergroup ([members #:mutable] ;; (CircularList Buffer)
|
||||||
[editor #:mutable] ;; (Option Editor), for bidirectional editor/group linkage
|
[editor #:mutable] ;; (Option Editor), for bidirectional editor/group linkage
|
||||||
) #:prefab)
|
) #:prefab)
|
||||||
|
|
||||||
(struct buffer ([rope #:mutable]
|
(struct buffer ([rope #:mutable]
|
||||||
[pos #:mutable]
|
|
||||||
[title #:mutable]
|
[title #:mutable]
|
||||||
[group #:mutable] ;; (Option BufferGroup)
|
[group #:mutable] ;; (Option BufferGroup)
|
||||||
[modeset #:mutable] ;; ModeSet
|
[modeset #:mutable] ;; ModeSet
|
||||||
|
@ -108,7 +111,6 @@
|
||||||
title ;; String
|
title ;; String
|
||||||
#:initial-contents [initial-contents ""])
|
#:initial-contents [initial-contents ""])
|
||||||
(register-buffer! group (buffer (initial-contents-rope initial-contents)
|
(register-buffer! group (buffer (initial-contents-rope initial-contents)
|
||||||
0
|
|
||||||
title
|
title
|
||||||
#f
|
#f
|
||||||
kernel-modeset)))
|
kernel-modeset)))
|
||||||
|
@ -129,7 +131,8 @@
|
||||||
|
|
||||||
(define (title->buffer* group title)
|
(define (title->buffer* group title)
|
||||||
(and group
|
(and group
|
||||||
(circular-list-memf (lambda (b) (equal? (buffer-title b) title)) (buffergroup-members group))))
|
(circular-list-memf (lambda (b) (equal? (buffer-title b) title))
|
||||||
|
(buffergroup-members group))))
|
||||||
|
|
||||||
(define (buffer->buffer* group b)
|
(define (buffer->buffer* group b)
|
||||||
(and group
|
(and group
|
||||||
|
@ -170,8 +173,7 @@
|
||||||
(let* ((filename (normalize-path (simplify-path filename)))
|
(let* ((filename (normalize-path (simplify-path filename)))
|
||||||
(title (filename->unique-buffer-title group filename))
|
(title (filename->unique-buffer-title group filename))
|
||||||
(b (make-buffer group title)))
|
(b (make-buffer group title)))
|
||||||
(buffer-replace-contents! b (string->rope (file->string filename)))
|
(buffer-replace-contents! b (string->rope (file->string filename)))))
|
||||||
(buffer-move-to! b 0)))
|
|
||||||
|
|
||||||
(define (buffer-rename! b new-title)
|
(define (buffer-rename! b new-title)
|
||||||
(if (title-exists-in-group? (buffer-group b) new-title)
|
(if (title-exists-in-group? (buffer-group b) new-title)
|
||||||
|
@ -197,8 +199,10 @@
|
||||||
(define g (buffer-group b))
|
(define g (buffer-group b))
|
||||||
(and g (buffergroup-editor g)))
|
(and g (buffergroup-editor g)))
|
||||||
|
|
||||||
(define (buffer-column buf)
|
(define (buffer-column buf pos-or-mtype)
|
||||||
(- (buffer-pos buf) (buffer-start-of-line buf)))
|
;; TODO: count actual columns!
|
||||||
|
(define pos (->pos buf pos-or-mtype 'buffer-column))
|
||||||
|
(- pos (buffer-start-of-line buf pos)))
|
||||||
|
|
||||||
(define (buffer-apply-modeset! buf modeset)
|
(define (buffer-apply-modeset! buf modeset)
|
||||||
(set-buffer-modeset! buf modeset))
|
(set-buffer-modeset! buf modeset))
|
||||||
|
@ -213,106 +217,101 @@
|
||||||
(define (clamp pos buf)
|
(define (clamp pos buf)
|
||||||
(max 0 (min (buffer-size buf) pos)))
|
(max 0 (min (buffer-size buf) pos)))
|
||||||
|
|
||||||
(define (buffer-move-to! buf pos0)
|
|
||||||
(define pos (clamp pos0 buf))
|
|
||||||
(set-buffer-pos! buf pos)
|
|
||||||
(buffer-seek! buf pos))
|
|
||||||
|
|
||||||
(define (buffer-seek! buf pos)
|
(define (buffer-seek! buf pos)
|
||||||
(buffer-lift rope-seek buf pos))
|
(buffer-lift rope-seek buf (clamp pos buf)))
|
||||||
|
|
||||||
(define (buffer-move-by! buf delta)
|
(define (buffer-start-of-line buf pos-or-mtype)
|
||||||
(buffer-move-to! buf (+ (buffer-pos buf) delta)))
|
(buffer-findf buf pos-or-mtype (lambda (ch) (equal? ch #\newline)) #:forward? #f))
|
||||||
|
|
||||||
(define (buffer-start-of-line buf)
|
(define (buffer-end-of-line buf pos-or-mtype)
|
||||||
(buffer-findf buf (lambda (ch) (equal? ch #\newline)) #:forward? #f))
|
(buffer-findf buf pos-or-mtype (lambda (ch) (equal? ch #\newline)) #:forward? #t))
|
||||||
|
|
||||||
(define (buffer-end-of-line buf)
|
(define (->pos buf pos-or-mtype what)
|
||||||
(buffer-findf buf (lambda (ch) (equal? ch #\newline)) #:forward? #t))
|
(clamp (if (number? pos-or-mtype)
|
||||||
|
pos-or-mtype
|
||||||
|
(buffer-mark-pos buf pos-or-mtype what))
|
||||||
|
buf))
|
||||||
|
|
||||||
(define (buffer-move-to-start-of-line! buf)
|
(define (buffer-mark-types buf)
|
||||||
(buffer-move-to! buf (buffer-start-of-line buf)))
|
(rope-marks (buffer-rope buf)))
|
||||||
|
|
||||||
(define (buffer-move-to-end-of-line! buf)
|
(define (buffer-mark* buf mtype)
|
||||||
(buffer-move-to! buf (buffer-end-of-line buf)))
|
(find-mark (buffer-rope buf) mtype))
|
||||||
|
|
||||||
(define (buffer-mark! buf [pos (buffer-pos buf)] #:mark-type [mtype main-mark-type] #:value [value #t])
|
(define (buffer-mark buf mtype [what 'buffer-mark])
|
||||||
(buffer-lift replace-mark buf mtype pos value))
|
(or (buffer-mark* buf mtype)
|
||||||
|
(error what "Mark type ~v not found; available mark types ~v" mtype (buffer-mark-types buf))))
|
||||||
|
|
||||||
(define (buffer-clear-mark! buf #:mark-type [mtype main-mark-type])
|
(define (buffer-mark-pos* buf mtype)
|
||||||
(define pos (find-mark-pos (buffer-rope buf) mtype))
|
(find-mark-pos (buffer-rope buf) mtype))
|
||||||
|
|
||||||
|
(define (buffer-mark-pos buf mtype [what 'buffer-mark-pos])
|
||||||
|
(or (buffer-mark-pos* buf mtype)
|
||||||
|
(error what "Mark type ~v not found; available mark types ~v" mtype (buffer-mark-types buf))))
|
||||||
|
|
||||||
|
(define (buffer-mark! buf mtype pos-or-mtype #:value [value #t])
|
||||||
|
(buffer-lift replace-mark buf mtype (->pos buf pos-or-mtype 'buffer-mark!) value))
|
||||||
|
|
||||||
|
(define (buffer-clear-mark! buf mtype)
|
||||||
|
(define pos (buffer-mark-pos* buf mtype))
|
||||||
(if pos
|
(if pos
|
||||||
(buffer-lift clear-mark buf mtype pos)
|
(buffer-lift clear-mark buf mtype pos)
|
||||||
buf))
|
buf))
|
||||||
|
|
||||||
(define (buffer-mark-pos buf [mtype main-mark-type])
|
(define (buffer-move-mark! buf mtype delta)
|
||||||
(find-mark-pos (buffer-rope buf) mtype))
|
(match-define (cons pos val) (buffer-mark buf mtype 'buffer-move-mark!))
|
||||||
|
(buffer-mark! buf mtype (+ pos delta) #:value val))
|
||||||
|
|
||||||
(define (buffer-region-split* buf pos mark)
|
(define (buffer-move-mark-to-start-of-line! buf mtype)
|
||||||
(define lo (clamp (min pos mark) buf))
|
(define pos (buffer-mark-pos buf mtype 'buffer-move-mark-to-start-of-line!))
|
||||||
(define hi (clamp (max pos mark) buf))
|
(buffer-mark! buf mtype (buffer-start-of-line buf pos)))
|
||||||
|
|
||||||
|
(define (buffer-move-mark-to-end-of-line! buf mtype)
|
||||||
|
(define pos (buffer-mark-pos buf mtype 'buffer-move-mark-to-end-of-line!))
|
||||||
|
(buffer-mark! buf mtype (buffer-end-of-line buf pos)))
|
||||||
|
|
||||||
|
(define (buffer-region-split buf pm1 pm2)
|
||||||
|
(define p1 (->pos buf pm1 'buffer-region-split))
|
||||||
|
(define p2 (->pos buf pm2 'buffer-region-split))
|
||||||
|
(define lo (min p1 p2))
|
||||||
|
(define hi (max p1 p2))
|
||||||
(define-values (l mr) (rope-split (buffer-rope buf) lo))
|
(define-values (l mr) (rope-split (buffer-rope buf) lo))
|
||||||
(define-values (m r) (rope-split mr (- hi lo)))
|
(define-values (m r) (rope-split mr (- hi lo)))
|
||||||
(values l lo m hi r))
|
(values l lo m hi r))
|
||||||
|
|
||||||
(define (buffer-region-split buf
|
(define (buffer-region buf pm1 pm2)
|
||||||
#:point [pos (buffer-pos buf)]
|
(define-values (_l _lo m _hi _r) (buffer-region-split buf pm1 pm2))
|
||||||
#:mark [mark (buffer-mark-pos buf)])
|
|
||||||
(buffer-region-split* buf pos mark))
|
|
||||||
|
|
||||||
(define (buffer-region buf
|
|
||||||
#:point [pos (buffer-pos buf)]
|
|
||||||
#:mark [mark (buffer-mark-pos buf)])
|
|
||||||
(define-values (_l _lo m _hi _r) (buffer-region-split* buf pos mark))
|
|
||||||
m)
|
m)
|
||||||
|
|
||||||
(define (buffer-region-update! buf updater
|
(define (transfer-marks ro rn)
|
||||||
#:point [pos (buffer-pos buf)]
|
(define mtypes-to-transfer
|
||||||
#:mark [mark (buffer-mark-pos buf)])
|
(for/list ((mtype (rope-marks ro))
|
||||||
(define-values (l lo old-m hi r) (buffer-region-split* buf pos mark))
|
#:when (buffer-mark-type-preserve? (mark-type-info mtype)))
|
||||||
(define new-m (updater old-m))
|
mtype))
|
||||||
|
(for/fold [(rn rn)] [(mtype mtypes-to-transfer)]
|
||||||
|
(define pos (case (mark-type-stickiness mtype)
|
||||||
|
[(left) 0]
|
||||||
|
[(right) (rope-size rn)]))
|
||||||
|
(set-mark rn mtype pos #t)))
|
||||||
|
|
||||||
|
(define (buffer-region-update! buf pm1 pm2 updater)
|
||||||
|
(define-values (l lo old-m hi r) (buffer-region-split buf pm1 pm2))
|
||||||
|
(define new-m (transfer-marks old-m (updater old-m)))
|
||||||
(define delta (- (rope-size new-m) (rope-size old-m)))
|
(define delta (- (rope-size new-m) (rope-size old-m)))
|
||||||
(set-buffer-rope! buf (rope-append (rope-append l new-m) r))
|
(set-buffer-rope! buf (rope-append (rope-append l new-m) r))
|
||||||
(cond
|
buf)
|
||||||
[(<= lo (buffer-pos buf) hi) (buffer-move-to! buf (+ hi delta))]
|
|
||||||
[(> (buffer-pos buf) hi) (buffer-move-by! buf delta)]
|
|
||||||
[else buf]))
|
|
||||||
|
|
||||||
(define (buffer-insert! buf content-rope
|
(define (buffer-insert! buf pos-or-mtype content-rope)
|
||||||
#:point [pos0 (buffer-pos buf)]
|
(define pos (->pos buf pos-or-mtype 'buffer-insert!))
|
||||||
#:move? [move? #t])
|
|
||||||
(define pos (clamp pos0 buf))
|
|
||||||
(define-values (l r) (rope-split (buffer-rope buf) pos))
|
(define-values (l r) (rope-split (buffer-rope buf) pos))
|
||||||
(set-buffer-rope! buf (rope-append (rope-append l content-rope) r))
|
(set-buffer-rope! buf (rope-append (rope-append l content-rope) r))
|
||||||
(when (>= (buffer-pos buf) pos)
|
|
||||||
(set-buffer-pos! buf (+ (buffer-pos buf) (rope-size content-rope))))
|
|
||||||
buf)
|
buf)
|
||||||
|
|
||||||
(define (buffer-replace-contents! buf content-rope)
|
(define (buffer-replace-contents! buf content-rope)
|
||||||
(buffer-region-update! buf (lambda (_dontcare) content-rope) #:point 0 #:mark (buffer-size buf)))
|
(buffer-region-update! buf 0 (buffer-size buf) (lambda (_dontcare) content-rope)))
|
||||||
|
|
||||||
(define (call-with-excursion buf f)
|
(define (buffer-search* buf start-pos-or-mtype forward? find-delta)
|
||||||
(define excursion (gensym 'excursion))
|
(define start-pos (->pos buf start-pos-or-mtype 'buffer-search*))
|
||||||
(define saved-mark-type (mark-type (format "Saved mark ~a" excursion) 'right))
|
|
||||||
(define saved-point-type (mark-type (format "Saved point ~a" excursion) 'right))
|
|
||||||
(buffer-mark! buf (buffer-mark-pos buf) #:mark-type saved-mark-type)
|
|
||||||
(buffer-mark! buf (buffer-pos buf) #:mark-type saved-point-type)
|
|
||||||
(define (restore!)
|
|
||||||
(define restore-mark-pos (buffer-mark-pos buf saved-mark-type))
|
|
||||||
(define restore-point-pos (buffer-mark-pos buf saved-point-type))
|
|
||||||
(when restore-mark-pos (buffer-mark! buf restore-mark-pos))
|
|
||||||
(when restore-point-pos (buffer-move-to! buf restore-point-pos))
|
|
||||||
(buffer-clear-mark! buf #:mark-type saved-mark-type)
|
|
||||||
(buffer-clear-mark! buf #:mark-type saved-point-type))
|
|
||||||
(with-handlers [(exn? (lambda (e)
|
|
||||||
(restore!)
|
|
||||||
(raise e)))]
|
|
||||||
(define result (f))
|
|
||||||
(restore!)
|
|
||||||
result))
|
|
||||||
|
|
||||||
(define (buffer-search* buf start-pos0 forward? move? find-delta)
|
|
||||||
(define start-pos (clamp start-pos0 buf))
|
|
||||||
(define-values (l r) (rope-split (buffer-rope buf) start-pos))
|
(define-values (l r) (rope-split (buffer-rope buf) start-pos))
|
||||||
(define delta (find-delta (if forward? r l)))
|
(define delta (find-delta (if forward? r l)))
|
||||||
(and delta
|
(and delta
|
||||||
|
@ -320,23 +319,15 @@
|
||||||
[forward? delta]
|
[forward? delta]
|
||||||
[else (- delta (rope-size l))]))
|
[else (- delta (rope-size l))]))
|
||||||
buf)))
|
buf)))
|
||||||
(if move?
|
(buffer-seek! buf new-pos)
|
||||||
(buffer-move-to! buf new-pos)
|
|
||||||
(buffer-seek! buf new-pos))
|
|
||||||
new-pos)))
|
new-pos)))
|
||||||
|
|
||||||
(define (buffer-search buf needle
|
(define (buffer-search buf start-pos-or-mtype needle #:forward? [forward? #t])
|
||||||
#:position [start-pos (buffer-pos buf)]
|
(buffer-search* buf start-pos-or-mtype forward?
|
||||||
#:forward? [forward? #t]
|
|
||||||
#:move? [move? #f])
|
|
||||||
(buffer-search* buf start-pos forward? move?
|
|
||||||
(lambda (piece) (search-rope needle piece #:forward? forward?))))
|
(lambda (piece) (search-rope needle piece #:forward? forward?))))
|
||||||
|
|
||||||
(define (buffer-findf buf f
|
(define (buffer-findf buf start-pos-or-mtype f #:forward? [forward? #t])
|
||||||
#:position [start-pos (buffer-pos buf)]
|
(buffer-search* buf start-pos-or-mtype forward?
|
||||||
#:forward? [forward? #t]
|
|
||||||
#:move? [move? #f])
|
|
||||||
(buffer-search* buf start-pos forward? move?
|
|
||||||
(lambda (piece) (findf-in-rope f piece #:forward? forward?))))
|
(lambda (piece) (findf-in-rope f piece #:forward? forward?))))
|
||||||
|
|
||||||
(define (buffer-lift f buf . args)
|
(define (buffer-lift f buf . args)
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
circular-list-map
|
circular-list-map
|
||||||
circular-list-filter
|
circular-list-filter
|
||||||
circular-list-remove
|
circular-list-remove
|
||||||
circular-list-memf)
|
circular-list-memf
|
||||||
|
circular-list-replacef)
|
||||||
|
|
||||||
(require racket/match)
|
(require racket/match)
|
||||||
|
(require (only-in racket/list splitf-at))
|
||||||
|
|
||||||
(struct circular-list ([front #:mutable]
|
(struct circular-list ([front #:mutable]
|
||||||
[back #:mutable]
|
[back #:mutable]
|
||||||
|
@ -130,6 +132,18 @@
|
||||||
(append seen (circular-list-back xs)))
|
(append seen (circular-list-back xs)))
|
||||||
(loop (cons a seen) (circular-cdr xs)))))))
|
(loop (cons a seen) (circular-cdr xs)))))))
|
||||||
|
|
||||||
|
(define (circular-list-replacef xs finder replacer)
|
||||||
|
(define (rejecter e) (not (finder e)))
|
||||||
|
(define-values (head tail) (splitf-at (circular-list-front xs) rejecter))
|
||||||
|
(if (null? tail)
|
||||||
|
(let-values (((head tail) (splitf-at (reverse (circular-list-back xs)) rejecter)))
|
||||||
|
(if (null? tail)
|
||||||
|
xs
|
||||||
|
(circular-list (circular-list-front xs)
|
||||||
|
(reverse (append head (replacer (car tail)) (cdr tail))))))
|
||||||
|
(circular-list (append head (replacer (car tail)) (cdr tail))
|
||||||
|
(circular-list-back xs))))
|
||||||
|
|
||||||
(module+ test
|
(module+ test
|
||||||
(require rackunit)
|
(require rackunit)
|
||||||
|
|
||||||
|
@ -149,6 +163,27 @@
|
||||||
(check-abcdef (circular-list '(a b c d e f) '()))
|
(check-abcdef (circular-list '(a b c d e f) '()))
|
||||||
(check-abcdef (circular-list '() '(f e d c b a)))
|
(check-abcdef (circular-list '() '(f e d c b a)))
|
||||||
|
|
||||||
|
(check-equal? (circular-list->list (circular-list-replacef (circular-list '(a b c) '(f e d))
|
||||||
|
(lambda (x) (eq? x 'e))
|
||||||
|
(lambda (x) (list 111))))
|
||||||
|
'(a b c d 111 f))
|
||||||
|
(check-equal? (circular-list->list (circular-list-replacef (circular-list '(a b c) '(f e d))
|
||||||
|
(lambda (x) (eq? x 'e))
|
||||||
|
(lambda (x) (list 111 222))))
|
||||||
|
'(a b c d 111 222 f))
|
||||||
|
(check-equal? (circular-list->list (circular-list-replacef (circular-list '(a b c) '(f e d))
|
||||||
|
(lambda (x) (eq? x 'b))
|
||||||
|
(lambda (x) (list 111))))
|
||||||
|
'(a 111 c d e f))
|
||||||
|
(check-equal? (circular-list->list (circular-list-replacef (circular-list '(a b c) '(f e d))
|
||||||
|
(lambda (x) (eq? x 'b))
|
||||||
|
(lambda (x) (list 111 222))))
|
||||||
|
'(a 111 222 c d e f))
|
||||||
|
(check-equal? (circular-list->list (circular-list-replacef (circular-list '(a b c) '(f e d))
|
||||||
|
(lambda (x) (eq? x 'x))
|
||||||
|
(lambda (x) (list 111 222))))
|
||||||
|
'(a b c d e f))
|
||||||
|
|
||||||
(check-equal? (match (circular-cons 1 circular-empty)
|
(check-equal? (match (circular-cons 1 circular-empty)
|
||||||
[(circular-cons a d) (cons a d)])
|
[(circular-cons a d) (cons a d)])
|
||||||
(cons 1 circular-empty))
|
(cons 1 circular-empty))
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
|
|
||||||
(provide (except-out (struct-out editor) editor)
|
(provide (except-out (struct-out editor) editor)
|
||||||
make-editor
|
make-editor
|
||||||
|
open-window
|
||||||
|
close-other-windows
|
||||||
|
close-window
|
||||||
|
resize-window
|
||||||
|
select-window
|
||||||
visit-file!
|
visit-file!
|
||||||
render-editor!
|
render-editor!
|
||||||
|
editor-next-window
|
||||||
|
editor-prev-window
|
||||||
editor-command
|
editor-command
|
||||||
editor-active-buffer
|
editor-active-buffer
|
||||||
editor-active-modeset
|
editor-active-modeset
|
||||||
|
@ -21,10 +28,11 @@
|
||||||
(require "mode.rkt")
|
(require "mode.rkt")
|
||||||
(require "keys.rkt")
|
(require "keys.rkt")
|
||||||
(require "rope.rkt")
|
(require "rope.rkt")
|
||||||
|
(require "circular-list.rkt")
|
||||||
|
|
||||||
(struct editor (buffers ;; BufferGroup
|
(struct editor (buffers ;; BufferGroup
|
||||||
[tty #:mutable] ;; Tty
|
[tty #:mutable] ;; Tty
|
||||||
[windows #:mutable] ;; (List (List Window SizeSpec)), abstract window layout
|
[windows #:mutable] ;; (CircularList (List Window SizeSpec)), abstract window layout
|
||||||
[active-window #:mutable] ;; (Option Window)
|
[active-window #:mutable] ;; (Option Window)
|
||||||
[running? #:mutable] ;; Boolean
|
[running? #:mutable] ;; Boolean
|
||||||
[default-modeset #:mutable] ;; ModeSet
|
[default-modeset #:mutable] ;; ModeSet
|
||||||
|
@ -37,7 +45,7 @@
|
||||||
(define w (make-window scratch))
|
(define w (make-window scratch))
|
||||||
(define e (editor g
|
(define e (editor g
|
||||||
tty
|
tty
|
||||||
(list (list w (relative-size 1)))
|
(list->circular-list (list (list w (relative-size 1))))
|
||||||
w
|
w
|
||||||
#f
|
#f
|
||||||
default-modeset))
|
default-modeset))
|
||||||
|
@ -55,13 +63,68 @@
|
||||||
(or (lookup-buffer g title)
|
(or (lookup-buffer g title)
|
||||||
(configure-fresh-buffer! editor (make-buffer g title #:initial-contents initial-contents))))
|
(configure-fresh-buffer! editor (make-buffer g title #:initial-contents initial-contents))))
|
||||||
|
|
||||||
|
(define (split-size s)
|
||||||
|
(match s
|
||||||
|
[(absolute-size _) s] ;; can't scale fixed-size windows
|
||||||
|
[(relative-size w) (relative-size (/ w 2))]))
|
||||||
|
|
||||||
|
(define (merge-sizes surviving disappearing)
|
||||||
|
(match* (surviving disappearing)
|
||||||
|
[((relative-size a) (relative-size b)) (relative-size (+ a b))]
|
||||||
|
[(_ _) surviving]))
|
||||||
|
|
||||||
|
(define (window-for-buffer editor buffer)
|
||||||
|
(cond [(circular-list-memf (lambda (e) (eq? (window-buffer (car e)) buffer))
|
||||||
|
(editor-windows editor)) => (compose car circular-car)]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
|
(define (entry-for? window) (lambda (e) (eq? (car e) window)))
|
||||||
|
|
||||||
|
(define (window->size-spec editor window)
|
||||||
|
(cond [(circular-list-memf (entry-for? window)
|
||||||
|
(editor-windows editor)) => (compose cadr circular-car)]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
|
(define (update-window-entry editor win updater)
|
||||||
|
(set-editor-windows! editor (circular-list-replacef (editor-windows editor)
|
||||||
|
(entry-for? win)
|
||||||
|
updater)))
|
||||||
|
|
||||||
(define (open-window editor buffer
|
(define (open-window editor buffer
|
||||||
#:size [size (relative-size 1)]
|
#:after-window [after-window (editor-active-window editor)]
|
||||||
|
#:proportional? [proportional? #f]
|
||||||
#:activate? [activate? #t])
|
#:activate? [activate? #t])
|
||||||
(define w (make-window buffer))
|
(define existing-w (window-for-buffer editor buffer))
|
||||||
(set-editor-windows! editor (append (editor-windows editor) (list (list w size))))
|
(define existing-size (window->size-spec editor after-window))
|
||||||
(when activate? (set-editor-active-window! editor w))
|
(define new-size (if proportional? existing-size (split-size existing-size)))
|
||||||
w)
|
(define new-point (or (and existing-w (buffer-mark-pos* buffer (window-point existing-w))) 0))
|
||||||
|
(define new-window (make-window buffer new-point))
|
||||||
|
(update-window-entry editor after-window
|
||||||
|
(lambda (e) (list (list after-window new-size)
|
||||||
|
(list new-window new-size))))
|
||||||
|
(when activate? (set-editor-active-window! editor new-window))
|
||||||
|
new-window)
|
||||||
|
|
||||||
|
(define (close-other-windows editor win)
|
||||||
|
(for ((entry (circular-list->list (editor-windows editor))) #:when (not (eq? (car entry) win)))
|
||||||
|
(set-window-buffer! (car entry) #f))
|
||||||
|
(set-editor-windows! editor (list->circular-list (list (list win (relative-size 1)))))
|
||||||
|
(set-editor-active-window! editor win))
|
||||||
|
|
||||||
|
(define (close-window editor win)
|
||||||
|
(define prev (editor-prev-window editor win))
|
||||||
|
(define prev-size (window->size-spec editor prev))
|
||||||
|
(define win-size (window->size-spec editor win))
|
||||||
|
(when (and prev (> (circular-length (editor-windows editor)) 1))
|
||||||
|
(when (eq? (editor-active-window editor) win) (set-editor-active-window! editor prev))
|
||||||
|
(update-window-entry editor win (lambda (e) '()))
|
||||||
|
(resize-window editor prev (merge-sizes prev-size win-size))))
|
||||||
|
|
||||||
|
(define (resize-window editor win size)
|
||||||
|
(update-window-entry editor win (lambda (e) (list (list win size)))))
|
||||||
|
|
||||||
|
(define (select-window editor win)
|
||||||
|
(set-editor-active-window! editor win))
|
||||||
|
|
||||||
(define (visit-file! editor filename)
|
(define (visit-file! editor filename)
|
||||||
(set-window-buffer! (editor-active-window editor)
|
(set-window-buffer! (editor-active-window editor)
|
||||||
|
@ -70,7 +133,7 @@
|
||||||
|
|
||||||
(define (render-editor! editor)
|
(define (render-editor! editor)
|
||||||
(render-windows! (editor-tty editor)
|
(render-windows! (editor-tty editor)
|
||||||
(editor-windows editor)
|
(circular-list->list (editor-windows editor))
|
||||||
(editor-active-window editor)))
|
(editor-active-window editor)))
|
||||||
|
|
||||||
(define (editor-active-buffer editor)
|
(define (editor-active-buffer editor)
|
||||||
|
@ -81,6 +144,20 @@
|
||||||
(define b (editor-active-buffer editor))
|
(define b (editor-active-buffer editor))
|
||||||
(and b (buffer-modeset b)))
|
(and b (buffer-modeset b)))
|
||||||
|
|
||||||
|
(define (editor-next-window editor win)
|
||||||
|
(cond [(circular-list-memf (entry-for? win)
|
||||||
|
(editor-windows editor)) => (compose car
|
||||||
|
circular-car
|
||||||
|
circular-list-rotate-forward)]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
|
(define (editor-prev-window editor win)
|
||||||
|
(cond [(circular-list-memf (entry-for? win)
|
||||||
|
(editor-windows editor)) => (compose car
|
||||||
|
circular-car
|
||||||
|
circular-list-rotate-backward)]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
(define (editor-command selector editor
|
(define (editor-command selector editor
|
||||||
#:keyseq [keyseq #f]
|
#:keyseq [keyseq #f]
|
||||||
#:prefix-arg [prefix-arg '#:default])
|
#:prefix-arg [prefix-arg '#:default])
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
|
|
||||||
(define fundamental-mode (make-mode "fundamental"))
|
(define fundamental-mode (make-mode "fundamental"))
|
||||||
|
|
||||||
(define-command fundamental-mode (self-insert-command buf #:keyseq keyseq)
|
(define-command fundamental-mode (self-insert-command buf #:window win #:keyseq keyseq)
|
||||||
(match keyseq
|
(match keyseq
|
||||||
[(list (key (? char? ch) modifiers)) #:when (set-empty? (set-remove modifiers 'shift))
|
[(list (key (? char? ch) modifiers)) #:when (set-empty? (set-remove modifiers 'shift))
|
||||||
(buffer-insert! buf (string->rope (string ch)))]
|
(buffer-insert! buf (window-point win) (string->rope (string ch)))]
|
||||||
[_ #f]))
|
[_ #f]))
|
||||||
|
|
||||||
(define-command fundamental-mode (unbound-key-sequence buf #:keyseq keyseq)
|
(define-command fundamental-mode (unbound-key-sequence buf #:keyseq keyseq)
|
||||||
|
@ -19,101 +19,119 @@
|
||||||
|
|
||||||
(define-key fundamental-mode (list "C-q" '#:default) self-insert-command)
|
(define-key fundamental-mode (list "C-q" '#:default) self-insert-command)
|
||||||
|
|
||||||
(define-command fundamental-mode (newline buf)
|
(define-command fundamental-mode (newline buf #:window win)
|
||||||
#:bind-key "C-m"
|
#:bind-key "C-m"
|
||||||
#:bind-key "C-j"
|
#:bind-key "C-j"
|
||||||
(buffer-insert! buf (string->rope "\n")))
|
(buffer-insert! buf (window-point win) (string->rope "\n")))
|
||||||
|
|
||||||
(define (move-forward-n-lines buf count)
|
(define (move-forward-n-lines win count)
|
||||||
|
(define buf (window-buffer win))
|
||||||
(for ((i count))
|
(for ((i count))
|
||||||
(buffer-move-to-end-of-line! buf)
|
(buffer-move-mark-to-end-of-line! buf (window-point win))
|
||||||
(buffer-move-by! buf 1)))
|
(buffer-move-mark! buf (window-point win) 1)))
|
||||||
|
|
||||||
(define (move-backward-n-lines buf count)
|
(define (move-backward-n-lines win count)
|
||||||
|
(define buf (window-buffer win))
|
||||||
(for ((i count))
|
(for ((i count))
|
||||||
(buffer-move-to-start-of-line! buf)
|
(buffer-move-mark-to-start-of-line! buf (window-point win))
|
||||||
(buffer-move-by! buf -1)))
|
(buffer-move-mark! buf (window-point win) -1)))
|
||||||
|
|
||||||
(define (move-to-column buf col)
|
(define (move-to-column win col)
|
||||||
(define eol-pos (buffer-end-of-line buf))
|
(define buf (window-buffer win))
|
||||||
(buffer-move-to-start-of-line! buf)
|
(define eol-pos (buffer-end-of-line buf (window-point win)))
|
||||||
(buffer-move-by! buf (min col (- eol-pos (buffer-pos buf)))))
|
(define sol-pos (buffer-start-of-line buf (window-point win)))
|
||||||
|
(buffer-mark! buf (window-point win) (+ sol-pos (min col (- eol-pos sol-pos)))))
|
||||||
|
|
||||||
(define-command fundamental-mode (forward-char buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (forward-char buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-f"
|
#:bind-key "C-f"
|
||||||
#:bind-key "<right>"
|
#:bind-key "<right>"
|
||||||
(buffer-move-by! buf count))
|
(buffer-move-mark! buf (window-point win) count))
|
||||||
|
|
||||||
(define-command fundamental-mode (backward-char buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (backward-char buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-b"
|
#:bind-key "C-b"
|
||||||
#:bind-key "<left>"
|
#:bind-key "<left>"
|
||||||
(buffer-move-by! buf (- count)))
|
(buffer-move-mark! buf (window-point win) (- count)))
|
||||||
|
|
||||||
(define-command fundamental-mode (next-line buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (next-line buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-n"
|
#:bind-key "C-n"
|
||||||
#:bind-key "<down>"
|
#:bind-key "<down>"
|
||||||
(define col (buffer-column buf))
|
(define col (buffer-column buf (window-point win)))
|
||||||
(move-forward-n-lines buf count)
|
(move-forward-n-lines win count)
|
||||||
(move-to-column buf col))
|
(move-to-column win col))
|
||||||
|
|
||||||
(define-command fundamental-mode (prev-line buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (prev-line buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-p"
|
#:bind-key "C-p"
|
||||||
#:bind-key "<up>"
|
#:bind-key "<up>"
|
||||||
(define col (buffer-column buf))
|
(define col (buffer-column buf (window-point win)))
|
||||||
(move-backward-n-lines buf count)
|
(move-backward-n-lines win count)
|
||||||
(move-to-column buf col))
|
(move-to-column win col))
|
||||||
|
|
||||||
(define-command fundamental-mode (move-end-of-line buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (move-end-of-line buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-e"
|
#:bind-key "C-e"
|
||||||
#:bind-key "<end>"
|
#:bind-key "<end>"
|
||||||
(when (positive? count) (move-forward-n-lines buf (- count 1)))
|
(when (positive? count) (move-forward-n-lines win (- count 1)))
|
||||||
(buffer-move-to-end-of-line! buf))
|
(buffer-move-mark-to-end-of-line! buf (window-point win)))
|
||||||
|
|
||||||
(define-command fundamental-mode (move-beginning-of-line buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (move-beginning-of-line buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "C-a"
|
#:bind-key "C-a"
|
||||||
#:bind-key "<home>"
|
#:bind-key "<home>"
|
||||||
(when (positive? count) (move-forward-n-lines buf (- count 1)))
|
(when (positive? count) (move-forward-n-lines win (- count 1)))
|
||||||
(buffer-move-to-start-of-line! buf))
|
(buffer-move-mark-to-start-of-line! buf (window-point win)))
|
||||||
|
|
||||||
(define-command fundamental-mode (delete-backward-char buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (delete-backward-char buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "<backspace>"
|
#:bind-key "<backspace>"
|
||||||
#:bind-key "C-h" ;; differs from GNU emacs
|
#:bind-key "C-h" ;; differs from GNU emacs
|
||||||
(buffer-region-update! buf
|
(define pos (buffer-mark-pos buf (window-point win)))
|
||||||
(lambda (_deleted) (empty-rope))
|
(buffer-region-update! buf (- pos 1) pos (lambda (_deleted) (empty-rope))))
|
||||||
#:mark (- (buffer-pos buf) count)))
|
|
||||||
|
|
||||||
(define-command fundamental-mode (delete-forward-char buf #:prefix-arg [count 1])
|
(define-command fundamental-mode (delete-forward-char buf #:window win #:prefix-arg [count 1])
|
||||||
#:bind-key "<delete>"
|
#:bind-key "<delete>"
|
||||||
#:bind-key "C-d"
|
#:bind-key "C-d"
|
||||||
(buffer-region-update! buf
|
(define pos (buffer-mark-pos buf (window-point win)))
|
||||||
(lambda (_deleted) (empty-rope))
|
(buffer-region-update! buf pos (+ pos 1) (lambda (_deleted) (empty-rope))))
|
||||||
#:mark (+ (buffer-pos buf) count)))
|
|
||||||
|
|
||||||
(define-command fundamental-mode (beginning-of-buffer buf #:prefix-arg [tenths 0])
|
(define-command fundamental-mode (beginning-of-buffer buf #:window win #:prefix-arg [tenths 0])
|
||||||
#:bind-key "M-<"
|
#:bind-key "M-<"
|
||||||
#:bind-key "C-<home>"
|
#:bind-key "C-<home>"
|
||||||
#:bind-key "<begin>"
|
#:bind-key "<begin>"
|
||||||
(if (eq? tenths '#:prefix) (set! tenths 0) (buffer-mark! buf))
|
(if (eq? tenths '#:prefix) (set! tenths 0) (window-mark! win))
|
||||||
(buffer-move-to! buf (* (buffer-size buf) (max 0 (min 10 tenths)) 1/10)))
|
(window-move-to! win (* (buffer-size buf) (max 0 (min 10 tenths)) 1/10)))
|
||||||
|
|
||||||
(define-command fundamental-mode (end-of-buffer buf #:prefix-arg [tenths 0])
|
(define-command fundamental-mode (end-of-buffer buf #:window win #:prefix-arg [tenths 0])
|
||||||
#:bind-key "M->"
|
#:bind-key "M->"
|
||||||
#:bind-key "C-<end>"
|
#:bind-key "C-<end>"
|
||||||
(if (eq? tenths '#:prefix) (set! tenths 0) (buffer-mark! buf))
|
(if (eq? tenths '#:prefix) (set! tenths 0) (window-mark! win))
|
||||||
(buffer-move-to! buf (* (buffer-size buf) (- 10 (max 0 (min 10 tenths))) 1/10)))
|
(window-move-to! win (* (buffer-size buf) (- 10 (max 0 (min 10 tenths))) 1/10)))
|
||||||
|
|
||||||
(define-command fundamental-mode (exchange-point-and-mark buf)
|
(define-command fundamental-mode (exchange-point-and-mark buf #:window win)
|
||||||
#:bind-key "C-x C-x"
|
#:bind-key "C-x C-x"
|
||||||
(define m (buffer-mark-pos buf))
|
(define m (buffer-mark-pos* buf (window-mark win)))
|
||||||
(when m
|
(when m
|
||||||
(define p (buffer-pos buf))
|
(define p (buffer-mark-pos buf (window-point win)))
|
||||||
(buffer-mark! buf p)
|
(window-mark! win p)
|
||||||
(buffer-move-to! buf m)))
|
(window-move-to! win m)))
|
||||||
|
|
||||||
(define-command fundamental-mode (set-mark-command buf #:prefix-arg arg)
|
(define-command fundamental-mode (set-mark-command buf #:window win #:prefix-arg arg)
|
||||||
#:bind-key "C-@"
|
#:bind-key "C-@"
|
||||||
#:bind-key "C-space"
|
#:bind-key "C-space"
|
||||||
(if (eq? arg '#:prefix)
|
(if (eq? arg '#:prefix)
|
||||||
(let ((m (buffer-mark-pos buf)))
|
(let ((m (buffer-mark-pos* buf (window-mark win))))
|
||||||
(and m (buffer-move-to! buf m)))
|
(and m (window-move-to! win m)))
|
||||||
(buffer-mark! buf)))
|
(window-mark! win (window-point win))))
|
||||||
|
|
||||||
|
(define-command fundamental-mode (split-window-below buf #:window win #:editor ed)
|
||||||
|
#:bind-key "C-x 2"
|
||||||
|
(open-window ed buf #:after-window win))
|
||||||
|
|
||||||
|
(define-command fundamental-mode (delete-other-windows buf #:window win #:editor ed)
|
||||||
|
#:bind-key "C-x 1"
|
||||||
|
(close-other-windows ed win))
|
||||||
|
|
||||||
|
(define-command fundamental-mode (delete-window buf #:window win #:editor ed)
|
||||||
|
#:bind-key "C-x 0"
|
||||||
|
(close-window ed win))
|
||||||
|
|
||||||
|
(define-command fundamental-mode (other-window buf #:window win #:editor ed)
|
||||||
|
#:bind-key "C-tab"
|
||||||
|
#:bind-key "C-x o"
|
||||||
|
(select-window ed (editor-next-window ed win)))
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(provide render-windows!)
|
(provide (struct-out absolute-size)
|
||||||
|
(struct-out relative-size)
|
||||||
|
render-windows!)
|
||||||
|
|
||||||
(require racket/match)
|
(require racket/match)
|
||||||
|
|
||||||
|
@ -9,7 +11,11 @@
|
||||||
(require "display.rkt")
|
(require "display.rkt")
|
||||||
(require "rope.rkt")
|
(require "rope.rkt")
|
||||||
|
|
||||||
(define top-of-window-mtype (mark-type "top-of-window" 'left))
|
;; A SizeSpec is either
|
||||||
|
;; -- (absolute-size PositiveInteger), a specific size in screen rows
|
||||||
|
;; -- (relative-size PositiveReal), a weighted window size
|
||||||
|
(struct absolute-size (lines) #:prefab)
|
||||||
|
(struct relative-size (weight) #:prefab)
|
||||||
|
|
||||||
(define (newline? c) (equal? c #\newline))
|
(define (newline? c) (equal? c #\newline))
|
||||||
(define (not-newline? c) (not (newline? c)))
|
(define (not-newline? c) (not (newline? c)))
|
||||||
|
@ -23,16 +29,16 @@
|
||||||
;; will end up at a configurable percentage of the way down the
|
;; will end up at a configurable percentage of the way down the
|
||||||
;; window.
|
;; window.
|
||||||
;;
|
;;
|
||||||
;; Buffer Nat -> Nat
|
;; Window Nat -> Nat
|
||||||
;; Ensures the given mark is sanely positioned as a top-of-window mark
|
;; Ensures that window-top is sanely positioned with respect to
|
||||||
;; with respect to the given cursor position. Returns the
|
;; window-point. Returns the new position of window-top.
|
||||||
;; top-of-window position.
|
(define (frame! win available-line-count
|
||||||
(define (frame-buffer! buf available-line-count
|
#:preferred-position-fraction [preferred-position-fraction 1/2])
|
||||||
#:preferred-position-fraction [preferred-position-fraction 1/2])
|
(define buf (window-buffer win))
|
||||||
(define old-top-of-window-pos (or (buffer-mark-pos buf top-of-window-mtype) 0))
|
(define old-top-of-window-pos (or (buffer-mark-pos* buf (window-top win)) 0))
|
||||||
(define preferred-distance-from-bottom
|
(define preferred-distance-from-bottom
|
||||||
(ceiling (* available-line-count (- 1 preferred-position-fraction))))
|
(ceiling (* available-line-count (- 1 preferred-position-fraction))))
|
||||||
(let loop ((pos (buffer-findf buf newline? #:forward? #f))
|
(let loop ((pos (buffer-findf buf (window-point win) newline? #:forward? #f))
|
||||||
(line-count 0)
|
(line-count 0)
|
||||||
(top-of-window-pos old-top-of-window-pos))
|
(top-of-window-pos old-top-of-window-pos))
|
||||||
(define new-top-of-window-pos
|
(define new-top-of-window-pos
|
||||||
|
@ -41,10 +47,10 @@
|
||||||
[(= pos old-top-of-window-pos)
|
[(= pos old-top-of-window-pos)
|
||||||
old-top-of-window-pos]
|
old-top-of-window-pos]
|
||||||
[(>= line-count (- available-line-count 1))
|
[(>= line-count (- available-line-count 1))
|
||||||
(buffer-mark! buf new-top-of-window-pos #:mark-type top-of-window-mtype)
|
(buffer-mark! buf (window-top win) new-top-of-window-pos)
|
||||||
new-top-of-window-pos]
|
new-top-of-window-pos]
|
||||||
[else
|
[else
|
||||||
(loop (buffer-findf buf newline? #:forward? #f #:position (- pos 1))
|
(loop (buffer-findf buf (- pos 1) newline? #:forward? #f)
|
||||||
(+ line-count 1)
|
(+ line-count 1)
|
||||||
new-top-of-window-pos)])))
|
new-top-of-window-pos)])))
|
||||||
|
|
||||||
|
@ -84,10 +90,11 @@
|
||||||
[_
|
[_
|
||||||
(emit (string c))])])))
|
(emit (string c))])])))
|
||||||
|
|
||||||
(define (render-buffer! t b window-top window-height is-active?)
|
(define (render-window! t win window-top window-height is-active?)
|
||||||
|
(define buf (window-buffer win))
|
||||||
(define available-line-count (- window-height 1))
|
(define available-line-count (- window-height 1))
|
||||||
(define top-of-window-pos (frame-buffer! b available-line-count))
|
(define top-of-window-pos (frame! win available-line-count))
|
||||||
(define cursor-pos (buffer-pos b))
|
(define cursor-pos (buffer-mark-pos buf (window-point win)))
|
||||||
(tty-goto t window-top 0)
|
(tty-goto t window-top 0)
|
||||||
(tty-body-style t is-active?)
|
(tty-body-style t is-active?)
|
||||||
(define cursor-coordinates
|
(define cursor-coordinates
|
||||||
|
@ -98,8 +105,8 @@
|
||||||
[(>= line-count available-line-count)
|
[(>= line-count available-line-count)
|
||||||
cursor-coordinates]
|
cursor-coordinates]
|
||||||
[else
|
[else
|
||||||
(define eol-pos (buffer-findf b newline? #:position sol-pos))
|
(define eol-pos (buffer-findf buf sol-pos newline?))
|
||||||
(define line (rope->string (buffer-region b #:point eol-pos #:mark sol-pos)))
|
(define line (rope->string (buffer-region buf sol-pos eol-pos)))
|
||||||
(define-values (formatted-line cursor-offset)
|
(define-values (formatted-line cursor-offset)
|
||||||
(format-line line (tty-columns t) (- cursor-pos sol-pos)))
|
(format-line line (tty-columns t) (- cursor-pos sol-pos)))
|
||||||
(tty-display t formatted-line)
|
(tty-display t formatted-line)
|
||||||
|
@ -111,8 +118,8 @@
|
||||||
(list (+ line-count window-top) cursor-offset)
|
(list (+ line-count window-top) cursor-offset)
|
||||||
cursor-coordinates))])))
|
cursor-coordinates))])))
|
||||||
(tty-statusline-style t is-active?)
|
(tty-statusline-style t is-active?)
|
||||||
(tty-display t (if is-active? "== " "-- ") (buffer-title b) " ")
|
(tty-display t (if is-active? "== " "-- ") (buffer-title buf) " ")
|
||||||
(let ((remaining-length (- (tty-columns t) 4 (string-length (buffer-title b)))))
|
(let ((remaining-length (- (tty-columns t) 4 (string-length (buffer-title buf)))))
|
||||||
(when (positive? remaining-length)
|
(when (positive? remaining-length)
|
||||||
(tty-display t (make-string remaining-length (if is-active? #\= #\-)))))
|
(tty-display t (make-string remaining-length (if is-active? #\= #\-)))))
|
||||||
cursor-coordinates)
|
cursor-coordinates)
|
||||||
|
@ -152,8 +159,7 @@
|
||||||
(for/fold [(cursor-position #f)] [(e layout)]
|
(for/fold [(cursor-position #f)] [(e layout)]
|
||||||
(match-define (list w window-top window-height) e)
|
(match-define (list w window-top window-height) e)
|
||||||
(define is-active? (eq? w active-window))
|
(define is-active? (eq? w active-window))
|
||||||
(define b (window-buffer w))
|
(define window-cursor-position (render-window! t w window-top window-height is-active?))
|
||||||
(define window-cursor-position (render-buffer! t b window-top window-height is-active?))
|
|
||||||
(if is-active? window-cursor-position cursor-position)))
|
(if is-active? window-cursor-position cursor-position)))
|
||||||
(when active-cursor-position
|
(when active-cursor-position
|
||||||
(tty-goto t (car active-cursor-position) (cadr active-cursor-position)))
|
(tty-goto t (car active-cursor-position) (cadr active-cursor-position)))
|
||||||
|
|
|
@ -48,9 +48,9 @@
|
||||||
;; Stickiness adheres. What Finseth calls a "normal mark" has 'right
|
;; Stickiness adheres. What Finseth calls a "normal mark" has 'right
|
||||||
;; stickiness, and what he calls a "fixed mark" has 'left stickiness.
|
;; stickiness, and what he calls a "fixed mark" has 'left stickiness.
|
||||||
|
|
||||||
;; A MarkType is a (mark-type String Stickiness). MarkTypes can be
|
;; A MarkType is a (mark-type Any Stickiness). MarkTypes can be
|
||||||
;; associated with a set of Any values at each position in the rope.
|
;; associated with a set of Any values at each position in the rope.
|
||||||
(struct mark-type (name stickiness) #:prefab)
|
(struct mark-type (info stickiness) #:prefab)
|
||||||
|
|
||||||
;; A Strand is a (strand String Number Number), representing a
|
;; A Strand is a (strand String Number Number), representing a
|
||||||
;; substring of a string.
|
;; substring of a string.
|
||||||
|
|
|
@ -1,46 +1,55 @@
|
||||||
#lang racket/base
|
#lang racket/base
|
||||||
|
|
||||||
(provide (except-out (struct-out window) window)
|
(provide (except-out (struct-out window) window set-window-buffer!)
|
||||||
(struct-out absolute-size)
|
(rename-out [set-window-buffer!* set-window-buffer!])
|
||||||
(struct-out relative-size)
|
|
||||||
make-window
|
make-window
|
||||||
window-split
|
|
||||||
window-command
|
window-command
|
||||||
|
window-mark!
|
||||||
|
window-move-to!
|
||||||
)
|
)
|
||||||
|
|
||||||
(require racket/match)
|
(require racket/match)
|
||||||
|
|
||||||
(require "buffer.rkt")
|
(require "buffer.rkt")
|
||||||
(require "lists.rkt")
|
(require "rope.rkt")
|
||||||
|
|
||||||
;; A SizeSpec is either
|
|
||||||
;; -- (absolute-size PositiveInteger), a specific size in screen rows
|
|
||||||
;; -- (relative-size PositiveReal), a weighted window size
|
|
||||||
(struct absolute-size (lines) #:prefab)
|
|
||||||
(struct relative-size (weight) #:prefab)
|
|
||||||
|
|
||||||
(struct window (id ;; Symbol
|
(struct window (id ;; Symbol
|
||||||
[buffer #:mutable] ;; Buffer
|
top ;; MarkType
|
||||||
|
point ;; MarkType
|
||||||
|
mark ;; MarkType
|
||||||
|
[buffer #:mutable] ;; (Option Buffer)
|
||||||
) #:prefab)
|
) #:prefab)
|
||||||
|
|
||||||
(define (make-window initial-buffer)
|
(define (make-window initial-buffer [initial-point-or-mark 0])
|
||||||
(window (gensym 'window)
|
(define id (gensym 'window))
|
||||||
initial-buffer))
|
(define w (window id
|
||||||
|
(mark-type (buffer-mark-type 'top id #f) 'left)
|
||||||
|
(mark-type (buffer-mark-type 'point id #t) 'right)
|
||||||
|
(mark-type (buffer-mark-type 'mark id #f) 'left)
|
||||||
|
#f))
|
||||||
|
(set-window-buffer!* w initial-buffer initial-point-or-mark) ;; sets initial marks
|
||||||
|
w)
|
||||||
|
|
||||||
(define (scale-size s)
|
(define (set-window-buffer!* win new [point-or-mark 0])
|
||||||
(match s
|
(define old (window-buffer win))
|
||||||
[(absolute-size _) s] ;; can't scale fixed-size windows
|
(when old
|
||||||
[(relative-size w) (relative-size (/ w 2))]))
|
(buffer-clear-mark! old (window-top win))
|
||||||
|
(buffer-clear-mark! old (window-point win))
|
||||||
(define (window-split w ws #:proportional? [proportional? #f])
|
(buffer-clear-mark! old (window-mark win)))
|
||||||
(replacef ws
|
(set-window-buffer! win new)
|
||||||
(lambda (e) (eq? (car e) w))
|
(when new
|
||||||
(lambda (e)
|
(buffer-mark! new (window-point win) point-or-mark))
|
||||||
(define new-size (if proportional? (cadr e) (scale-size (cadr e))))
|
(void))
|
||||||
(list (list w new-size)
|
|
||||||
(list (make-window (window-buffer w)) new-size)))))
|
|
||||||
|
|
||||||
(define (window-command selector window
|
(define (window-command selector window
|
||||||
#:keyseq [keyseq #f]
|
#:keyseq [keyseq #f]
|
||||||
#:prefix-arg [prefix-arg '#:default])
|
#:prefix-arg [prefix-arg '#:default])
|
||||||
(command selector (window-buffer window) #:window window #:keyseq keyseq #:prefix-arg prefix-arg))
|
(command selector (window-buffer window) #:window window #:keyseq keyseq #:prefix-arg prefix-arg))
|
||||||
|
|
||||||
|
(define (window-mark! win [pos (window-point win)])
|
||||||
|
(buffer-mark! (window-buffer win) (window-mark win) pos)
|
||||||
|
win)
|
||||||
|
|
||||||
|
(define (window-move-to! win pos)
|
||||||
|
(buffer-mark! (window-buffer win) (window-point win) pos)
|
||||||
|
win)
|
||||||
|
|
Loading…
Reference in New Issue