commander-s/scheme/nuit-engine.scm

1097 lines
31 KiB
Scheme

;; ,load /home/demattia/studium/studienarbeit/scsh-nuit/scheme/nuit-engine.scm
;;This is the "heart" of NUIT.
;;In a central loop the program waits for input (with wgetch).
;;In the upper buffer simply the functionalities of scsh-ncurses:
;;input-buffer are used.
;;The lower window is meant to be used more flexible. Depending on
;;the active command the key-inputs are routed to the correct receiver,
;;where one can specify how to react.
;;*************************************************************************
;;State
(define-record-type app-window :app-window
(make-app-window x y width height curses-win)
app-window?
(x app-window-x)
(y app-window-y)
(width app-window-width)
(height app-window-height)
(curses-win app-window-curses-win set-app-window-curses-win!))
(define bar-1 #f)
(define bar-2 #f)
(define command-frame-window #f)
(define command-window #f)
(define result-window #f)
(define shortcuts '("F1:Exit"
"F2:Repaint (after change of buffer size)"
"Ctrl+x o:Switch Buffer"
"Ctrl+x s:Insert/Select"
"Ctrl+x u:-/Unselect"
"PageUp - previous entry in result history"
"PageDown - next entry in result history"
"Ctrl+x r:Redo (Active Command)"
"CursorUp - previous entry in command history"
"CursorDown - next entry in command history"
"Ctrl+a:First Pos of Line"
"Ctrl+e:End of Line"
"Ctrl+k:Delete Line"))
;;state of the upper window (Command-Window)
(define command-buffer
(make-buffer '("Welcome to the scsh-ncurses-ui!" "")
2 2 2 1 1
0 0
#t 1))
;;state of the lower window (Result-Window)
;;----------------------------
;;Text
(define text-result (list "Type 'shortcuts' for help"))
;;line of the result-window
(define pos-result 0)
;;column
(define pos-result-col 0)
;;y-coordinate of the cursor in the result-buffer
(define result-buffer-pos-y 0)
;;x-coordinate of the cursor in the result-buffer
(define result-buffer-pos-x 0)
;;lines of the lower window
(define result-lines 0)
;;columns in the lower window
(define result-cols 0)
;;lines to be highlighted
(define highlighted-lines '())
;;lines to be marked
(define marked-lines '())
;;miscelaneous state
;;-------------------
(define *focus-buffer* 'command-buffer)
(define (focus-on-command-buffer?)
(eq? *focus-buffer* 'command-buffer))
(define (focus-command-buffer!)
(set! *focus-buffer* 'command-buffer))
(define (focus-on-result-buffer?)
(eq? *focus-buffer* 'result-buffer))
(define (focus-result-buffer!)
(set! *focus-buffer* 'result-buffer))
;;History
(define history '())
;;Position in the "elaborated" History
(define history-pos 0)
;;data-type for history.entries
(define-record-type history-entry history-entry
(make-history-entry command
parameters
result-object)
history-entry?
(command history-entry-command)
(parameters history-entry-parameters)
(result-object history-entry-result-object))
;;active command
(define active-command "")
;;sctive parameters
(define active-parameters "")
;;active result-object
(define current-result-object)
;;active keyboard-interrupt:
;;after each input this is set to #f.
;;If a keyboard-interrupt occurs this can be checked by looking-up this box
(define active-keyboard-interrupt #f)
;;This indicates if the last input was Ctrl-x
(define c-x-pressed #f)
;;Message-Types
;;---------------------
;;A new command was entered
;;->create a new "object"
(define-record-type next-command-message next-command-message
(make-next-command-message command-string
parameters
width)
next-command-message?
(command-string next-command-string)
(parameters next-command-message-parameters)
(width next-command-message-width))
;;key pressed
;;The object and the key are send to the user-code, who returns the
;;changed object.
(define-record-type key-pressed-message key-pressed-message
(make-key-pressed-message command-string
result-model
key)
key-pressed-message?
(command-string key-pressed-command-string)
(result-model key-pressed-message-result-model)
(key key-pressed-message-key))
;;print
(define-record-type print-message print-message
(make-print-message command-string
object
width)
print-message?
(command-string print-message-command-string)
(object print-message-object)
(width print-message-width))
;;->this sort of data-type is returned by a print-message
(define-record-type print-object print-object
(make-print-object pos-y
pos-x
text
highlighted-lines
marked-lines)
(pos-y print-object-pos-y)
(pos-x print-object-pos-x)
(text print-object-text)
(highlighted-lines print-object-highlighted-lines)
(marked-lines print-object-marked-lines))
;;restore (when side-effects occur)
(define-record-type restore-message restore-message
(make-restore-message command-string
object)
restore-message?
(command-string restore-message-command-string)
(object restore-message-object))
;;request the selection
(define-record-type selection-message selection-message
(make-selection-message command-string
object)
selection-message?
(command-string selection-message-command-string)
(object selection-message-object))
;;The "user" (who extends the functionality of NUIT) has to inform NUIT
;;about which function is meant to be the receiver, when a certain
;;command is active
(define-record-type receiver receiver
(make-receiver command rec)
receiver?
(command receiver-command)
(rec receiver-rec))
;;This list contains all the receivers that have been registered.
(define receivers '())
;;*************************************************************************
;;Actions
;;start the whole thing
(define (nuit)
(with-inspecting-handler
8888
(lambda (condition)
(with-current-output-port*
(error-output-port)
(lambda ()
(display "starting remote handler for condition")
(display condition)
(newline)
(display "Please connect to port 8888")
(newline)
#t)))
run))
;;handle input
(define (run)
'(set-interrupt-handler interrupt/keyboard
(lambda a
(set! active-keyboard-interrupt a)))
;;Loop
(paint)
(let loop ((ch (wait-for-input)))
(cond
;;The result of pressing these keys is independent of which
;;Buffer is active
;;Finish
((= ch key-f1)
(begin
(let ((restore-message (make-restore-message
active-command
current-result-object)))
(switch restore-message)
(restore-state))
(endwin)
(display "")))
((= ch key-f2)
(endwin)
(run))
;;Ctrl-x -> wait for next input
((= ch 24)
(begin
(set! c-x-pressed (not c-x-pressed))
(if (focus-on-result-buffer?)
(let ((key-message
(make-key-pressed-message active-command
current-result-object
ch)))
(set! current-result-object (switch key-message))))
(paint)
(loop (wait-for-input))))
;; forward in result history
((= ch key-npage)
(history-forward)
(paint-result-window)
(loop (wait-for-input)))
;; back in result history
((= ch key-ppage)
(history-back)
(paint-result-window)
(loop (wait-for-input)))
;;if lower window is active a message is sent.
(else
(if c-x-pressed
(cond
;;Ctrl-x o ->switch buffer
((= ch 111)
(if (focus-on-command-buffer?)
(let ((key-message
(make-key-pressed-message active-command
current-result-object
97)))
(focus-result-buffer!)
(set! current-result-object (switch key-message))
(paint-result-window))
(begin
(focus-command-buffer!)
(paint-command-window-contents)
(set! command-buffer (move-cursor command-buffer))))
(set! c-x-pressed #f)
(loop (wait-for-input)))
;;C-x r -> redo
((= ch 114)
(if (or (> (length (buffer-text command-buffer)) 2)
(not (equal? active-command "")))
(let ((command-string (string-append active-command
active-parameters))
(text (sublist (buffer-text command-buffer) 0
(- (length (buffer-text command-buffer)) 1))))
(begin
(switch restore-message)
(set-buffer-text! (append text (list command-string)))
(execute-command)
(set-buffer-history-pos! command-buffer
(- (length (buffer-text command-buffer)) 1))
(set! c-x-pressed #f)
(endwin)
(run)))
(begin
(set! c-x-pressed #f)
(loop (wait-for-input)))))
(else
(begin
(if (focus-on-result-buffer?)
(let ((key-message
(make-key-pressed-message active-command
current-result-object
ch)))
(set! current-result-object (switch key-message)))
(if (= ch 115)
(let* ((message
(make-selection-message
active-command current-result-object))
(marked-items (switch message)))
(add-string-to-command-buffer marked-items))))
(set! c-x-pressed #f)
(loop (wait-for-input)))))
(if (focus-on-result-buffer?)
(let ((key-message
(make-key-pressed-message active-command
current-result-object
ch)))
(set! current-result-object (switch key-message))
(paint-result-window)
(loop (wait-for-input)))
(cond
;;Enter
((= ch 10)
(let ((restore-message (make-restore-message
active-command
current-result-object)))
(switch restore-message)
(execute-command)
(set-buffer-history-pos!
command-buffer
(- (length (buffer-text command-buffer)) 1))
(paint-result-window)
(paint-bar-2)
(paint-command-window-contents)
(set! command-buffer (move-cursor command-buffer))
(loop (wait-for-input))))
(else
(set! command-buffer (input command-buffer ch))
(werase (app-window-curses-win command-window))
(print-command-buffer (app-window-curses-win command-window)
command-buffer)
(set! command-buffer (move-cursor command-buffer))
(loop (wait-for-input))))))))))
(define (window-init-curses-win! window)
(set-app-window-curses-win!
window
(newwin (app-window-height window) (app-window-width window)
(app-window-y window) (app-window-x window))))
(define (init-windows!)
(init-screen)
(set! bar-1
(make-app-window 1 1
(- (COLS) 2) 2
#f))
(set! bar-2
(make-app-window 1 (+ (round (/ (LINES) 3)) 2)
(- (COLS) 2) 3
#f))
(set! command-frame-window
(make-app-window 1 2
(- (COLS) 2) (- (app-window-y bar-2) 2)
#f))
(set! command-window
(make-app-window (+ (app-window-x command-frame-window) 1)
(+ (app-window-y command-frame-window) 1)
(- (app-window-width command-frame-window) 2)
(- (app-window-height command-frame-window) 2)
#f))
(set! result-window
(make-app-window 1 (+ (app-window-y bar-2) 3)
(- (COLS) 2)
(- (- (LINES) 6) (app-window-height command-frame-window))
#f))
(window-init-curses-win! bar-1)
(window-init-curses-win! bar-2)
(window-init-curses-win! command-frame-window)
(window-init-curses-win! command-window)
(window-init-curses-win! result-window)
(wclear (app-window-curses-win bar-1))
(wclear (app-window-curses-win bar-2))
(wclear (app-window-curses-win command-window))
(wclear (app-window-curses-win command-frame-window))
(wclear (app-window-curses-win result-window))
(clear))
(define (paint-bar-1)
(mvwaddstr (app-window-curses-win bar-1) 0 1 "SCSH-NUIT")
(wrefresh (app-window-curses-win bar-1)))
(define (paint-bar-2)
(box (app-window-curses-win bar-2) (ascii->char 0) (ascii->char 0))
(print-active-command-win (app-window-curses-win bar-2)
(app-window-width bar-2)))
(define (paint-command-frame-window)
(box (app-window-curses-win command-frame-window)
(ascii->char 0) (ascii->char 0))
(wrefresh (app-window-curses-win command-frame-window)))
(define (paint-command-window-contents)
(set-buffer-num-lines! command-buffer
(- (app-window-height command-window) 2))
(set-buffer-num-cols! command-buffer
(- (app-window-width command-window) 3))
(werase (app-window-curses-win command-window))
(set! command-buffer
(print-command-buffer (app-window-curses-win command-window)
command-buffer))
(wrefresh (app-window-curses-win command-window)))
(define (paint-result-window)
(wclear (app-window-curses-win result-window))
(box (app-window-curses-win result-window)
(ascii->char 0) (ascii->char 0))
(set! result-lines (- (app-window-height result-window) 2))
(set! result-cols (- (app-window-width result-window) 3))
(print-result-buffer result-window)
(wrefresh (app-window-curses-win result-window)))
(define (paint)
(init-windows!)
(paint-bar-1)
(paint-bar-2)
(paint-command-frame-window)
(paint-command-window-contents)
(paint-result-window)
(move-cursor command-buffer))
(define (wait-for-input)
(noecho)
(keypad (app-window-curses-win bar-1) #t)
(set! active-keyboard-interrupt #f)
(let ((ch (wgetch (app-window-curses-win bar-1))))
(echo)
ch))
;;If the user presses enter the last line is interpreted as a command
;;which has to be executed.
(define (execute-command)
(let* ((com (list-ref (buffer-text command-buffer)
(- (length (buffer-text command-buffer)) 1)))
(com-par (extract-com-and-par com))
(command (car com-par))
(parameters (cdr com-par))
;;todo: parameters
(message (make-next-command-message
command parameters result-cols))
(model (switch message)))
(if (not (= history-pos 0))
(let ((hist-entry (make-history-entry active-command
active-parameters
current-result-object))
(active (make-history-entry command
(get-param-as-str parameters)
model)))
(if (< history-pos (length history))
(set! history (append history (list hist-entry)))
(set! history (append
(sublist history 0
(- (length history) 1))
(list hist-entry) (list active))))
(set! history-pos (length history)))
(let ((hist-entry (make-history-entry
command
(get-param-as-str parameters) model)))
(set! history (list hist-entry))
(set! history-pos 1)))
(set-buffer-text! command-buffer
(append (buffer-text command-buffer)
(list "")))
(set! active-command command)
(set! active-parameters (get-param-as-str parameters))
(set! current-result-object model)
(scroll-command-buffer)))
;;Extracts the name of the function and its parameters
(define extract-com-and-par
(lambda (com)
(if (<= (string-length com) 0)
(cons "" '())
(if (equal? #\( (string-ref com 0))
(cons com '())
(let* ((fst-word (get-next-word com))
(command (car fst-word))
(rest (cdr fst-word)))
(let loop ((param-str rest)
(param-list '()))
(let* ((word (get-next-word param-str))
(param (car word))
(more (cdr word)))
(if (equal? "" param)
(cons command param-list)
(loop more (append param-list (list param)))))))))))
;;gets the next word from a string
(define get-next-word
(lambda (str)
(let loop ((old str)
(new ""))
(if (= 0 (string-length old))
(cons new old)
(if (equal? #\space (string-ref old 0))
(if (= 1 (string-length old))
(cons new "")
(cons new (substring old 1 (string-length old))))
(if (equal? #\( (string-ref old 0))
(let* ((nw (get-next-word-braces
(substring old 1
(string-length old))))
(nw-new (car nw))
(nw-old (cdr nw)))
(loop nw-old (string-append new "(" nw-new)))
(loop (substring old 1 (string-length old))
(string-append new (string (string-ref old 0))))))))))
(define get-next-word-braces
(lambda (str)
(let loop ((old str)
(new ""))
(if (= 0 (string-length old))
(cons new old)
(if (equal? #\( (string-ref old 0))
(let* ((nw (get-next-word-braces
(substring old 1
(string-length old))))
(nw-new (car nw))
(nw-old (cdr nw)))
(loop nw-old (string-append new "(" nw-new)))
(if (equal? #\) (string-ref old 0))
(cons (string-append new ")")
(substring old 1 (string-length old)))
(loop (substring old 1 (string-length old))
(string-append new (string (string-ref old 0))))))))))
;;scroll buffer after one command was entered
(define (scroll-command-buffer)
(set-buffer-pos-line! command-buffer
(+ (buffer-pos-line command-buffer) 1))
(set-buffer-pos-col! command-buffer 2))
;;evaluate an expression given as a string
(define evaluate
(lambda (exp)
(let* ((command-port (open-input-string exp))
(handler (lambda (condition more)
(cons 'Error: condition)))
(structure (reify-structure 'scheme-with-scsh))
(s (load-structure structure))
(env (rt-structure->environment structure))
(result (with-fatal-error-handler
handler
(eval (read command-port) env))))
result)))
;;Message-Passing
;;switch manages that the messages are delivered in the correct way
(define switch
(lambda (message)
(let ((command ""))
(begin
(cond
((next-command-message? message)
(set! command (next-command-string message)))
((key-pressed-message? message)
(set! command (key-pressed-command-string message)))
((print-message? message)
(set! command (print-message-command-string message)))
((restore-message? message)
(set! command (restore-message-command-string message)))
((selection-message? message)
(set! command (selection-message-command-string message))))
(let ((receiver (get-receiver command)))
(if receiver
(receiver message)
(standard-receiver message)))))))
(define get-receiver
(lambda (command)
(let loop ((recs receivers))
(if (= 0 (length recs))
#f
(let* ((act-rec (car recs))
(act-com (receiver-command act-rec))
(act-rec-proc (receiver-rec act-rec)))
(if (equal? command act-com)
act-rec-proc
(loop (cdr recs))))))))
;;Management of the upper buffer
;;add a char to the buffer
(define (add-to-command-buffer ch)
(let* ((text (buffer-text command-buffer))
(last-pos (- (length text) 1))
(old-last-el (list-ref text last-pos))
(old-rest (sublist text 0 last-pos))
(before-ch (substring old-last-el 0
(max 0 (- (buffer-pos-col command-buffer) 2))))
(after-ch (substring old-last-el
(max 0 (- (buffer-pos-col command-buffer) 2))
(string-length old-last-el)))
(new-last-el (string-append before-ch
(string (ascii->char ch))
after-ch)))
(set-buffer-text! command-buffer
(append old-rest (list new-last-el)))
(set-buffer-pos-col! command-buffer
(+ (buffer-pos-col command-buffer) 1))))
;;add a string to the buffer
(define add-string-to-command-buffer
(lambda (string)
(let loop ((str string))
(if (equal? str "")
(values)
(let ((first-ch (string-ref str 0)))
(begin
(add-to-command-buffer (char->ascii first-ch))
(loop (substring str 1 (string-length str)))))))))
;;selection of the visible area of the buffer
(define prepare-lines
(lambda (l height pos)
(if (< (length l) height)
(let loop ((tmp-list l))
(if (= height (length tmp-list))
tmp-list
(loop (append tmp-list (list "")))))
(if (< pos height)
(sublist l 0 height)
(sublist l (- pos height) height)))))
;;print the active-command window:
(define print-active-command-win
(lambda (win width)
(if (<= width 25)
(values)
(let ((active-command (string-append active-command
active-parameters)))
(if (> (string-length active-command) (- width 25))
(let* ((com-txt (substring active-command
0
(- width 25)))
(whole-text (string-append "Active Command: "
com-txt
"...")))
(begin
(mvwaddstr win 1 2 whole-text)
(wrefresh win)))
(begin
(mvwaddstr win 1 2 (string-append "Active Command: "
active-command))
(wrefresh win)))))))
;;print the lower window
(define (print-result-buffer result-window)
(let* ((window (app-window-curses-win result-window))
(print-message (make-print-message active-command
current-result-object
(buffer-num-cols command-buffer)))
(model (switch print-message))
(text (print-object-text model))
(pos-y (print-object-pos-y model))
(pos-x (print-object-pos-x model))
(highlighted-lns (print-object-highlighted-lines model))
(marked-lns (print-object-marked-lines model)))
(set! text-result text)
(set! pos-result pos-y)
(set! pos-result-col pos-x)
(set! highlighted-lines highlighted-lns)
(set! marked-lines marked-lns)
(right-highlighted-lines)
(right-marked-lines)
(let ((lines (get-right-result-lines)))
(let loop ((pos 1))
(if (> pos result-lines)
(values)
(let ((line (list-ref lines (- pos 1))))
(begin
(if (not (standard-result-obj? current-result-object))
(set! line
(if (> (string-length line) result-cols)
(let ((start-line
(substring line 0
(- (ceiling (/ result-cols 2))
3)))
(end-line
(substring line
(- (string-length line)
(ceiling
(/ result-cols 2)))
(string-length line))))
(string-append start-line "..." end-line))
line)))
(if (and (member pos highlighted-lines)
(focus-on-result-buffer?))
(begin
(wattron window (A-REVERSE))
(mvwaddstr window pos 1 line)
(wattrset window (A-NORMAL))
(wrefresh window)
(loop (+ pos 1)))
(if (member pos marked-lines)
(begin
(wattron window (A-BOLD))
(mvwaddstr window pos 1 line)
(wattrset window (A-NORMAL))
(wrefresh window)
(loop (+ pos 1)))
(begin
(mvwaddstr window pos 1 line)
(wrefresh window)
(loop (+ pos 1))))))))))))
;;visible lines
(define get-right-result-lines
(lambda ()
(prepare-lines text-result result-lines pos-result)))
;;marked and highlighted lines
(define right-highlighted-lines
(lambda ()
(let loop ((old highlighted-lines)
(new '()))
(if (equal? '() old)
(set! highlighted-lines new)
(let ((el (car old)))
(if (<= pos-result result-lines)
;;auf der ersten Seite
(loop (cdr old)
(append new (list el)))
(let* ((offset (- pos-result result-lines))
(new-el (- el offset )))
(loop (cdr old)
(append new (list new-el))))))))))
(define right-marked-lines
(lambda ()
(let loop ((old marked-lines)
(new '()))
(if (equal? '() old)
(set! marked-lines new)
(let ((el (car old)))
(if (<= pos-result result-lines)
;;auf der ersten Seite
(loop (cdr old)
(append new (list el)))
(let* ((offset (- pos-result result-lines))
(new-el (- el offset )))
(loop (cdr old)
(append new (list new-el))))))))))
;;Cursor
;;move cursor to the corrct position
(define (move-cursor buffer)
(if (focus-on-command-buffer?)
(cursor-right-pos (app-window-curses-win command-window)
buffer)
(begin
(compute-y-x)
(wmove (app-window-curses-win result-window)
result-buffer-pos-y result-buffer-pos-x)
(wrefresh (app-window-curses-win result-window))
buffer)))
;;compue pos-x and pos-y
(define compute-y-x
(lambda ()
(if (focus-on-command-buffer?)
(begin
(if (>= (buffer-pos-fin-ln command-buffer)
(buffer-num-lines command-buffer))
(set-buffer-pos-y! command-buffer
(buffer-num-lines command-buffer))
(set-buffer-pos-y! command-buffer
(buffer-pos-fin-ln command-buffer)))
(let ((posx (modulo (buffer-pos-col command-buffer)
(buffer-num-cols command-buffer))))
(set-buffer-pos-x! command-buffer posx)))
(begin
(if (>= pos-result result-lines)
(set! result-buffer-pos-y result-lines)
(set! result-buffer-pos-y pos-result))
(set! result-buffer-pos-x pos-result-col)))))
; ;;index of shortcuts at the bottom
; (define print-bar3
; (lambda (width)
; (let loop ((pos 0)
; (used-width 0)
; (act-line 1))
; (if (>= pos (length shortcuts))
; (begin
; (let* ((num-blanks (+ (- width used-width) 1))
; (last-string (make-string num-blanks #\space)))
; (mvwaddstr bar3 act-line (+ used-width 1) last-string))
; (wrefresh bar3))
; (let* ((act-string (list-ref shortcuts pos))
; (act-length (string-length act-string))
; (rest-width (- width used-width)))
; (if (= act-line 1)
; (if (<= (+ act-length 3) rest-width)
; (if (= used-width 0)
; (begin
; (mvwaddstr bar3 1 (+ used-width 1) act-string)
; (loop (+ pos 1) (+ used-width act-length) 1))
; (begin
; (mvwaddstr bar3 1 (+ used-width 1)
; (string-append " | " act-string))
; (loop (+ pos 1) (+ used-width (+ 3 act-length))
; 1)))
; (begin
; (let* ((num-blanks (+ rest-width 1))
; (last-string (make-string num-blanks #\space)))
; (mvwaddstr bar3 1 (+ used-width 1) last-string))
; (loop pos 0 2)))
; (if (<= (+ act-length 3) rest-width)
; (if (= used-width 0)
; (begin
; (mvwaddstr bar3 2 (+ used-width 1) act-string)
; (loop (+ pos 1) (+ used-width act-length) 2))
; (begin
; (mvwaddstr bar3 2 (+ used-width 1)
; (string-append " | " act-string))
; (loop (+ pos 1) (+ used-width (+ 3 act-length)) 2)))
; (begin
; (let* ((num-blanks (+ rest-width 1) )
; (last-string (make-string num-blanks #\space)))
; (mvwaddstr bar3 2 (+ used-width 1) last-string))
; (wrefresh bar3)))))))))
;; one step back in the history
(define history-back
(lambda ()
(if (<= history-pos 0)
(values)
(let* ((hist-entry (list-ref history (- history-pos 1)))
(entry-com (history-entry-command hist-entry))
(entry-par (history-entry-parameters hist-entry))
(entry-res-obj (history-entry-result-object hist-entry)))
(begin
(set! active-command entry-com)
(set! active-parameters entry-par)
(set! current-result-object entry-res-obj)
(if (> history-pos 1)
(set! history-pos (- history-pos 1))))))))
;;one step forward
(define history-forward
(lambda ()
(if (> history-pos (- (length history) 1))
(values)
(let* ((hist-entry (list-ref history history-pos))
(entry-com (history-entry-command hist-entry))
(entry-par (history-entry-parameters hist-entry))
(entry-res-obj (history-entry-result-object hist-entry)))
(begin
(set! active-command entry-com)
(set! active-parameters entry-par)
(set! current-result-object entry-res-obj)
(set! history-pos (+ history-pos 1)))))))
(define sublist
(lambda (l pos k)
(let ((tmp (list-tail l pos)))
(reverse (list-tail (reverse tmp)
(- (length tmp) k))))))
;;When NUIT is closed the state has to be restored, in order to let the
;;user start again from scratch
(define restore-state
(lambda ()
(begin
(set! text-result (list "Start entering commands."))
(set! pos-result 0)
(set! pos-result-col 0)
(set! result-buffer-pos-y 0)
(set! result-buffer-pos-x 0)
(set! result-lines 0)
(set! result-cols 0)
(set! highlighted-lines '())
(set! marked-lines '())
(set! history '())
(set! history-pos 0)
(set! active-command "")
(set! active-parameters "")
(set! current-result-object init-std-res)
(set! active-keyboard-interrupt #f))))
;;Shortcuts-receiver:
;;-------------------
;;If the user enters the command "shortcuts" a list of the included
;;shortcuts is displayed
(define-record-type shortcut-result-obj shortcut-result-obj
(make-shortcut-result-obj a)
shortcut-result-object?
(a shortcut-result-object-a))
(define shortcut-receiver
(lambda (message)
(cond
((next-command-message? message)
(make-shortcut-result-obj #t))
((print-message? message)
(make-print-object 1 1 shortcuts '() '()))
((key-pressed-message? message)
(key-pressed-message-result-model message))
((restore-message? message)
(values))
((selection-message? message)
""))))
(define shortcut-rec (make-receiver "shortcuts" shortcut-receiver))
(set! receivers (cons shortcut-rec receivers))
;;Standard-Receiver
;;-----------------
;;Datatype representing the "standard-result-objects"
(define-record-type standard-result-obj standard-result-obj
(make-standard-result-obj cursor-pos-y
cursor-pos-x
result-text
result)
standard-result-obj?
(cursor-pos-y standard-result-obj-cur-pos-y)
(cursor-pos-x standard-result-obj-cur-pos-x)
(result-text standard-result-obj-result-text)
(result standard-result-obj-result))
(define init-std-res (make-standard-result-obj 1 1 text-result
(car text-result)))
(set! current-result-object init-std-res)
;;Standard-Receiver:
(define standard-receiver
(lambda (message)
(cond
((next-command-message? message)
(let* ((command (next-command-string message))
(result (evaluate command))
(result-string (exp->string result))
(width (next-command-message-width message)))
(let* ((text
(layout-result-standard result-string result width))
(std-obj
(make-standard-result-obj 1 1 text result)))
std-obj)))
((print-message? message)
(let* ((model (print-message-object message))
(pos-y (standard-result-obj-cur-pos-y model))
(pos-x (standard-result-obj-cur-pos-x model))
(width (print-message-width message))
(result (standard-result-obj-result model))
(text (layout-result-standard (exp->string result)
result width)))
(make-print-object pos-y pos-x text '() '())))
((key-pressed-message? message)
(key-pressed-message-result-model message))
((restore-message? message)
(values))
((selection-message? message)
""))))
;;the result is the "answer" of scsh
(define layout-result-standard
(lambda (result-str result width)
(reverse (seperate-line result-str width))))
;useful helpers
(define get-marked-positions-1
(lambda (all-items marked-items)
(let loop ((count 0)
(result '()))
(if (>= count (length all-items))
result
(let ((act-item (list-ref all-items count)))
(if (member act-item marked-items)
(loop (+ count 1)
(append result (list (+ count 1))))
(loop (+ count 1) result)))))))
(define get-marked-positions-2
(lambda (all-items marked-items)
(let loop ((count 0)
(result '()))
(if (>= count (length all-items))
result
(let ((act-item (list-ref all-items count)))
(if (member act-item marked-items)
(loop (+ count 1)
(append result (list (+ count 2))))
(loop (+ count 1) result)))))))
(define get-marked-positions-3
(lambda (all-items marked-items)
(let loop ((count 0)
(result '()))
(if (>= count (length all-items))
result
(let ((act-item (list-ref all-items count)))
(if (member act-item marked-items)
(loop (+ count 1)
(append result (list (+ count 3))))
(loop (+ count 1) result)))))))
;;expression as string
(define exp->string
(lambda (exp)
(let ((exp-port (open-output-string)))
(begin
(write exp exp-port)
(get-output-string exp-port)))))
;;seperate a long line into pieces, each fitting into a smaller line.
(define seperate-line
(lambda (line width)
(let loop ((new '())
(old line))
(if (> width (string-length old))
(if (= 0 (string-length old))
(if (equal? new '())
'("")
new)
(append (list old) new))
(let ((next-line (substring old 0 width))
(rest-old (substring old width (string-length old))))
(loop (cons next-line new) rest-old))))))
(define get-param-as-str
(lambda (param-lst)
(let loop ((lst param-lst)
(str ""))
(if (null? lst)
str
(loop (cdr lst)
(string-append str " " (car lst)))))))